Why does the type class Functor
have only the memberfmap
? I often find it useful to perform a fold over datatypes. Say, hierarchical ones, like a tree.
Note that a map
is a special case of fold
, that is, the latter is more fundamental. I guess I can take it the way it is, but maybe there is a reason?
Because a Functor
is a very general kind of object; not all Functor
s support folds. For example, there is an instance1
instance Functor (a ->) where
-- > fmap :: (b -> c) -> (a -> b) -> (a -> c)
fmap f g = g . f
But, while (a ->)
is a Functor
for all a
, for infinite a
there isn't a reasonable fold
definition. (Incidentally, a 'fold' in general is a catamorphism, which means it has a different type for each functor. The Foldable
type class defines it for sequence-like types.).
Consider what the foldr
definition for Integer -> Integer
would look like; what would the outermost application be? What would the value of
foldr (\ _ n -> 1 + n) 0 (\ n -> n + 1)
be? There isn't a reasonable definition of fold
without a lot more structure on the argument type.
1(a ->)
isn't legal Haskell for some reason. But I'm going to use it anyway as a more readable version of (->) a
, since I think it's easier for a novice to understand.
The abstraction you are looking for is Foldable
: This is a type class providing variuos forms of fold
.
There is also Traversable
for things where you can “fold while changing”, comparable to the mapAccumL
function for lists.
It is actually not true that fmap
is a special case of fold
, as pointed out by @DietrichEpp, see as here are possible non-Functor instances of Foldable.
map
is however a special case of mapAccumL
(no surprise, given the name), and hence the definition of Traversable
requires the thing to be also a Functor
and a Foldable
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With