Reputation:
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.
Upvotes: 2
Views: 262
Reputation: 53901
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''' ....
Upvotes: 3
Reputation: 6778
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 (>>)
Upvotes: 4