考虑以下功能:在Haskell monad/left-lifting中使用纯函数?
foo =
[1,2,3] >>=
return . (*2) . (+1)
为了更好的可读性和逻辑,我想(*2)
和(+1)
移动我的纯函数的返回的左侧。我可以这样实现这一点:
infixr 9 <.
(<.) :: (a -> b) -> (b -> c) -> (a -> c)
(<.) f g = g . f
bar =
[1,2,3] >>=
(+1) <.
(*2) <.
return
不过,我不喜欢的(<.)
右关联性。
让我们介绍一个功能leftLift
:
leftLift :: Monad m => (a -> b) -> a -> m b
leftLift f = return . f
baz =
[1,2,3] >>=
leftLift (+1) >>=
leftLift (*2) >>=
return
我很喜欢这一点。另一种可能性是定义的bind
变体:
infixl 1 >>$
(>>$) :: Monad m => m a -> (a -> b) -> m b
(>>$) m f = m >>= return . f
qux =
[1,2,3] >>$
(+1) >>$
(*2) >>=
return
我不知道这是否是一个好主意,因为它不会允许我使用do
符号我应该希望如此。 leftLift
我可以do
使用:
bazDo = do
x <- [1,2,3]
y <- leftLift (+1) x
z <- leftLift (*2) y
return z
我没有找到的leftLift
上的签名Hoogle功能。这样的功能是否存在?如果它叫什么?如果不是,我应该怎么称呼它?什么是我正在尝试做的最习惯的方式?
编辑:这是一个被@邓禄普的回答以下的启发版本:
infixl 4 <&>
(<&>) :: Functor f => f a -> (a -> b) -> f b
(<&>) = flip fmap
blah =
[1,2,3] <&>
(+1) <&>
(*2) >>=
return
我还要补充一点,我是一个bind
后-variant,因为我想写我的代码点免费样式。对于do
-notation,我想我不需要“假装”我做了任何单调的事情,所以我可以使用let
s。
我发现自己使用'= <比'>> ='更经常地与组成和普通应用保持一致。这很好地避免了第一个例子中的方向反转。 – Ben
这很好,我没有意识到这一点。然后我可以写回报。 (* 2)。 (+1)= << [1,2,3]'。而且,是的,正如@ user2297560所说,可读性是非常主观的。 –