Foldable and Traversable vs. FunctorM

Isaac Dupree ml at isaac.cedarswampstudios.org
Fri Feb 27 08:37:31 EST 2009


Henning Thielemann wrote:
> ? However 'foldMap' cannot utilize the additional information, namely
> Position and (Maybe e), respectively. In the first case this is sad, in
> the second case I consider this bad, since it is too easy to throw away
> and thus ignore the exception (Maybe e). Some kind of fold is always
> useful on these structures, but 'foldMap' is too limited.

I'm not sure what you mean, but if you define Traversable in a sensible way, 
then you can define Foldable with Data.Traversable.foldMapDefault and get a 
sensible definition.

>   Even more, consider a data structure like StorableVector which requires
> certain properties of its elements. StorableVector is intended for Int,
> Double and other Storable types, but you cannot store (IO Double) values.
> This example is not practical, because the Storable restriction disallows
> to define both Traversable and FunctorM instances. However you see, that
> one cannot even imagine 'sequence' on StorableVector, whereas 'mapM' is
> possible, yet very inefficient (needs copying the entire vector for each
> added element).

Sure you can define 'sequence'... because you cannot construct a StorableVector 
with elements that are not Storable.  (You could save this information inside 
the StorableVector using existentials/GADTs.)   Except...

> My conclusion is, that FunctorM was better than its reputation, and that
> Traversable as it is, is not what I need most of the time. What are the
> experiences of other Traversable users?

that the fundamental complaint is that Traversables must be in Functor which 
requires to accomodate all types of kind *.  On the other hand, as you note, 
either FunctorM or Traversable instance requires that property as well.  (cf. 
Data.Traversable.fmapDefault, which uses "traverse" to define it)

Basically, if you can make a type Traversable by defining
(Traversable t) : traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
then this is almost always just as easy as defining 
(FunctorM f) : fmapM :: Monad m => (a -> m b) -> f a -> m (f b)
for that type.
(note that the type signatures are almost the same, and have almost equal 
power.  Assuming you didn't want to do weird monadic more-complicated-than-
Applicative things, that is.)

In other words, my experience is that Traversable is more beautiful and no 
less usable.

-Isaac



More information about the Libraries mailing list