Question

For example, suppose I have the following functions:

foo :: Monad f => f a
bar :: Monad f => a -> f b
baz :: Monad f => a -> f c
qux :: Monad f => a -> f d

And I only want to return the result of qux, e.g. g :: Monad f => f a -> f d, where g calls bar and baz for their side-effects, perhaps.

Is there a way to construct g without explicitly applying each function to the result of foo? Somewhat similar to how (&&&) works, or (<*>) I suppose.

Was it helpful?

Solution 2

I'm assuming that a b c and d are in fact not supposed to be type variables and instead you meant more like

 data A
 data B
 data C
 data D

Because otherwise you're asking for a function of type forall a b. a -> b which is impossible to meaningfully create.

k = Kleisli
a &^& b = a &&& b >>> arr snd
g = runKleisli $ k bar &^& k baz &^& k quux

is a simple way to do this. it uses the kleisli arrow which wraps around a Monad to lift it into arrow land. I'm not aware of any nice combinators that accomplish &^& in a predefined way but it's pretty trivial to define.

The nice thing is that this scales trivially and is pointfree

 g = runKleisli $ k f &^& k f' &^& k f'' &^& k f''' ....

OTHER TIPS

Here's a possible solution using the Monad instance for ((->) r). This works nicely, and scales to as many function applications as neccessary.

g :: Monad m => m a -> m b
g foo = foo >>= bar .&. baz .&. qux
    where (.&.) = liftM2 (>>)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top