
The NICTA course https://github.com/NICTA/course includes exercises on the type class Extend, in Course/Extend.hs. Extend is a superclass of Comonad. Here's the class definition:
-- | All instances of the `Extend` type-class must satisfy one law. This law -- is not checked by the compiler. This law is given as: -- -- * The law of associativity -- `∀f g. (f <<=) . (g <<=) ≅ (<<=) (f . (g <<=))` class Functor f => Extend f where -- Pronounced, extend. (<<=) :: (f a -> b) -> f a -> f b
infixr 1 <<=
Could someone please motivate the Extend instance for List? (Its implementation is left as an exercise. In the course, type List a is isomorphic to [a].) Some of the tests (<<=) is expected to pass are shown, and make clear what ought to happen.
-- | Implement the @Extend@ instance for @List@. -- -- >>> length <<= ('a' :. 'b' :. 'c' :. Nil) -- [3,2,1] -- -- >>> id <<= (1 :. 2 :. 3 :. 4 :. Nil) -- [[1,2,3,4],[2,3,4],[3,4],[4]] -- -- >>> reverse <<= ((1 :. 2 :. 3 :. Nil) :. (4 :. 5 :. 6 :. Nil) :. Nil) -- [[[4,5,6],[1,2,3]],[[4,5,6]]]
The following (wrong, according to the tests) Extend instance for List nevertheless obeys the types and obeys the Extend law of associativity.
instance Extend List where (<<=) :: (List a -> b) -> List a -> List b (<<=) f = (:. Nil) . f (:. Nil) is analogous to (: []), create a singleton list.
I can't find a good reference on the Extend type class to convince me why the correct Extend instance for List in the course is the desirable one. (I'm not saying my version is desirable, in fact it seems fairly useless, but it works.) Graham