Contravariant functor subclass
rightfold opened this issue · 4 comments
It is useful to have:
class (Contravariant f) <= Contrafilterable f where
cfilter :: forall a. (a -> Boolean) -> f a -> f a
cfilterCmap :: forall a b. (b -> Maybe a) -> f a -> f b
cpartition :: ...
cpartitionCmap :: ...
An example use case is my logging library, which currently provides this method as a function: https://pursuit.purescript.org/packages/purescript-logging/0.0.3/docs/Control.Logger#v:cfilter
Thanks, I've been thinking about this. Although I haven't tested it; I think we can define these in terms of Decidable. Something like:
cfilterCmap :: forall a b f. Decidable f => (a -> Maybe b) -> f b -> f a
cfilterCmap f = choose (maybe (Left unit) Right <<< f) conquer
I'm also thinking about a Profunctor
version.
Very interesting! It seems Logger
is an instance of Decidable
.
I've been thinking about this for a while. If we look at the types:
choose :: (a -> b + c) -> f b * f c -> f a
altMap :: (b + c -> a) -> f b * f c -> f a
altMap f l r = map f (alt (map Left l) (map Right r))
The difference here is that the function argument has been reversed.
Now if we compare partitionMap
with choose
:
choose :: (a -> b + c) -> f b * f c -> f a
partitionMap :: (a -> b + c) -> f a -> f b * f c
The function argument is the same. If instead we reverse the function argument,
as in the difference between altMap
and choose
, we get a kind of forking
behaviour:
forkMap :: (b + c -> a) -> f a -> f b * f c
partitionMap :: (a -> b + c) -> f a -> f b * f c
However, forkMap
appears to be implementable just with cmap
:
forkMap f = cmap (f <<< Left) &&& cmap (f <<< Right)
So now I'm a little confused 😄.
What if in addition to reversing the function argument, you swap out *
for +
in the result?