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