例如,假设我有以下功能:
foo :: Monad f => f a
bar :: Monad f => a -> f b
baz :: Monad f => a -> f c
qux :: Monad f => a -> f d
我只想返回qux
的结果,例如g :: Monad f => f a -> f d
,
其中g
可能会调用bar
和baz
的副作用。
有没有办法构建g
而不明确将每个函数应用于foo
的结果?与(&&&)
的工作方式有些相似,或者我认为是(<*>)
。
答案 0 :(得分:4)
这是使用Monad
((->) r)
实例的可能解决方案。这很好用,并且可以扩展到必要的功能应用程序。
g :: Monad m => m a -> m b
g foo = foo >>= bar .&. baz .&. qux
where (.&.) = liftM2 (>>)
答案 1 :(得分:3)
我假设a
b
c
和d
实际上不应该是类型变量,而是你的意思更像
data A
data B
data C
data D
因为否则你要求的是forall a b. a -> b
类型的函数,这是不可能有意义地创建的。
k = Kleisli
a &^& b = a &&& b >>> arr snd
g = runKleisli $ k bar &^& k baz &^& k quux
是一种简单的方法。它使用围绕Monad的kleisli箭头将其抬起到箭头之地。我不知道有任何漂亮的组合器以预定义的方式完成&^&
,但定义起来非常简单。
好消息是,这可以简单地缩放并且是无点的
g = runKleisli $ k f &^& k f' &^& k f'' &^& k f''' ....