Many functions can be generalised

wren romano wren at
Mon Nov 28 21:41:08 UTC 2016

On Sun, Nov 27, 2016 at 9:08 AM, Lana Black <lanablack at> wrote:
> On 07:10 Sun 27 Nov     , Baldur Blöndal wrote:
>> > catMaybes :: (Foldable f)             => f (Maybe a) -> [a]
>> > catMaybes :: (Foldable f, Foldable g) => f (g     a) -> [a]
>> > catMaybes = foldMap toList
>> > mapMaybes ::               (a -> Maybe b) -> (forall f. Foldable f => f a
>> -> [b])
>> > mapMaybes :: Foldable m => (a -> m     b) -> (forall f. Foldable f => f a
>> -> [b])
>> > mapMaybes f = foldMap (toList . f)
> These two as well as 'filter' are generalized in witherable[1].
> [1]:

I'm also -1 to the OP. If we want to do these sorts of
generalizations, then we should use something like witherable and get
that API to where everyone agrees it captures the right concept. Just
because we *can* go polymorphic as above doesn't mean those are the
proper generalizations. Anything sequential can be made into lists,
but that doesn't mean lists are appropriate; lists lose a lot of
information. I'd much rather see the above functions as:

    mapMaybes :: Foo f => (a -> Maybe b) -> f a -> f b
    catMaybes :: Foo f => f (Maybe a) -> f a

Note how the f-structure is retained, rather than being needlessly
converted to a list. The above signatures capture the idea that f is
"sparse" and can absorb missing values, which is a coherent concept
that should have some nice laws we can exploit to clean up our code.
Indeed, the Witherable class takes this approach (though it has an
unfortunate Traversable dependency I don't think is always

Live well,

More information about the Libraries mailing list