How does Haskell deal with abstracting the functor? It uses the typeclass mechanism.
A typeclass defines a family of types that support a common interface.
class Eq a where (==) :: a -> b -> Bool
- If you want to tell Haskell that a particular type is
Eq
, you have to declare it an instance of this class and provide the implementation of(==).
data Point = Pt Float Float instance Eq Pt where (==) :: (Pt x1 y1) -> (Pt x2 y2) = x1 == x2 && y1 == y2
- Notice that, unlike in C++ or Java, you don’t have to specify the
Eq
class (or interface) when definingPoint
— you can do it later in client code. Typeclasses are also Haskell’s only mechanism for overloading functions (and operators). We will need that for overloadingfmap
for different functors. - There is one complication, though: a functor is not defined as a type but as a mapping of types (a type constructor). We need a typeclass that’s not a family of types, as was the case with
Eq
, but a family of type constructors. Fortunately a Haskell typeclass works with type constructors as well as with types. So here’s the definition of theFunctor
class:class Functor f where fmap :: (a -> b) -> f a -> f b
-
instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just f(a)
-
data List a = Nil | Con a (List a) instance Functor List where fmap _ Nil = Nil fmap f (Con a list) = Con (f a) (fmap f list)
Functor Laws (Composition and Identity)
Reader Functor
Combination of the type constructor(->) r
with the below implementation offmap
is called the reader functor. -
data (->) r a instance Functor ((->) r) where -- fmap :: (a -> b) -> (r -> a) -> (r -> b) fmap f g = f . g -- or (.) f g or fmap = (.)
Functors as Containers
Haskell’s laziness, a traditional container, like a list, may actually be implemented as a function. Consider, for instance, an infinite list of natural numbers, which can be compactly defined as:nats :: [Integer] nats = [1..]
Functor Composition
A composition of two functors, when acting on objects, is just the composition of their respective object mappings; and similarly when acting on morphisms.Bi-Functors
Since functors are morphisms in Cat (the category of categories), a lot of intuitions about morphisms — and functions in particular — apply to functors as well.
Writer Functor
type Writer a = (a, String)
(>=>) :: (a -> Writer b) -> (b -> Writer c) -> (a -> Writer c) m1 >=> m2 = \x -> let (y, s1) = m1 x (z, s2) = m2 y in (z, s1 ++ s2)
return :: a -> Writer a return x = (x, "")
fmap f = id >=> (\x -> return (f x))