Proposal: Add Foldable and Traversable instances for ((,) a)

These instances are pretty obvious, and no more or less trivial than the existing instances for Prelude types. I have found them to be useful.
instance Foldable ((,) a) where foldMap f (_, y) = f y foldr f z (_, y) = f y z foldl f z (_, y) = f z y foldr1 _ (_, y) = y foldl1 _ (_, y) = y
instance Traversable ((,) a) where traverse f (x, y) = (,) x <$> f y
In the spirit of the world's finest legislative bodies, I am attaching two unrelated amendments to this proposal. One amendment is to add a few additional explicit method implementations in the Foldable and Traversable instances for Prelude types. These might sometimes be slightly more efficient, and they better match the strictness and style of the existing explicit method implementations. For lists:
sequence = Control.Monad.sequence
For Maybe:
foldMap _ Nothing = mempty foldMap f (Just x) = f x
foldr1 _ Nothing = error "foldr1 of Nothing" foldr1 _ (Just x) = x
foldl1 _ Nothing = error "foldl1 of Nothing" foldl1 _ (Just x) = x
For arrays:
foldl f z = Prelude.foldl f z . elems foldr1 f = Prelude.foldr1 f . elems foldl1 f = Prelude.foldl1 f . elems
The other amendment is to fix the documentation for the functions fmapDefault and foldMapDefault in Data.Traversable. Contrary to what is stated, these cannot be used as methods in superclasses, since the superclasses must already exist before these functions can be defined. Instead, I have paraphrased what is stated in the documentation above: that the corresponding superclass methods should be equivalent to these. http://hackage.haskell.org/trac/ghc/ticket/3324 Discussion period: two weeks.

On Tue, Jun 23, 2009 at 03:07:04PM +0300, Yitzchak Gale wrote:
The other amendment is to fix the documentation for the functions fmapDefault and foldMapDefault in Data.Traversable. Contrary to what is stated, these cannot be used as methods in superclasses, since the superclasses must already exist before these functions can be defined. Instead, I have paraphrased what is stated in the documentation above: that the corresponding superclass methods should be equivalent to these.
The intention is that if you only want to define Traversable, you can fill in the required superclass instances by defining instance Functor F where fmap = fmapDefault instance Foldable F where foldMap = foldMapDefault instance Traversable F where traverse = ... That should work fine. However the fmap definition won't work if you defined sequenceA instead of traverse, so the documentation of fmapDefault needs to be corrected to say that.

I wrote:
...fmapDefault and foldMapDefault... cannot be used as methods in superclasses, since the superclasses must already exist before these functions can be defined.
Ross Paterson wrote:
The intention is that if you only want to define Traversable, you can fill in the required superclass instances by defining
instance Functor F where fmap = fmapDefault
instance Foldable F where foldMap = foldMapDefault
instance Traversable F where traverse = ...
That should work fine.
Cool, I didn't know that works. On the other hand, in general, that mechanism sounds a bit dangerous. It could lead to infinite recursion that would be very difficult to debug in the case of a complex class dependency graph, couldn't it?
However the fmap definition won't work if you defined sequenceA instead of traverse, so the documentation of fmapDefault needs to be corrected to say that.
Case in point. OK, how about this: In the documentation for class Traversable, change (`fmapDefault`) to (see `fmapDefault`), similarly for foldMapDefault. Documentation for fmapDefault: -- | This function should be equivalent to `fmap` in -- the `Functor` superclass instance. If you do not -- already have a `Functor` instance, you can use -- this function to define one: -- -- > instance Functor T where -- > fmap = fmapDefault -- -- Note, however, that this will lead to infinite -- recursion if you did not provide an explicit -- implementation of the `traverse` method. Documentation for foldMapDefault: -- | This function should be equivalent to `foldMap` in -- the `Foldable` superclass instance. If you do not -- already have a `Foldable` instance, you -- can use this function to define one: -- -- > instance Functor T where -- > fmap = fmapDefault Thanks, Yitz

Oops, correcting cut-and-paste error: Documentation for foldMapDefault: -- This function should be equivalent to `foldMap` in -- the `Foldable` superclass instance. If you do not -- already have a `Foldable` instance, you -- can use this function to define one: -- -- > instance Foldable T where -- > foldMap = foldMapDefault
participants (2)
-
Ross Paterson
-
Yitzchak Gale