Many functions can be generalised

David Feuer david.feuer at gmail.com
Mon Dec 5 00:33:16 UTC 2016


On Sun, Dec 4, 2016 at 6:45 PM, David Menendez <dave at zednenem.com> wrote:

>> Surely you can do the same with the constructor class.
>>
>> newtype Ab a = Ab (a -> Bool)
>> instance Siftable Ab where
>>   siftAway _ = Ab (const False)
>>   sift p (Ab g) = Ab ...
>
>
> Ab is contravariant, so you would need something like
>
> siftContraMap :: (a -> Maybe b) -> f b -> f a

That's the Functor version, which entirely excludes contravariant
things. For the plain sift :: (a -> Bool) -> f a -> f a version, you
can use

instance Siftable Ab where
  sift f (Ab g) = Ab (\x -> g x && f x)
  siftAway (Ab g) = Ab (const False)

>> I'm not sure if my siftAway excludes anything it shouldn't....
>
> I’m not sure it’s possible to define siftAway so that it isn’t equal to sift
> (const Nothing).

As you pointed out, your laws for the plain Siftable don't exclude
sift _ = id for an arbitrary Siftable. Adding siftAway with that law
ensures that sift (const Nothing) actually "empties" the container. I
doubt it actually makes sense to add it to the API, though.

As for names, I think for consistency with the rest of the world, the
method names that make the most sense are filter, mapMaybe, filterM,
and traverseMaybe. The filterM name is a bit unfortunate, since it
only needs an Applicative constraint, but that seems to be what people
like. The monad-extras package uses the name mapMaybeM, but that
strikes me as a terrible name because it's really much more like
traverse than like map.

David


More information about the Libraries mailing list