1

考虑以下函数:

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

我没有在 Hoogle 上找到签名为leftLift. 这样的函数是否存在,如果存在,它叫什么?如果不是,我应该怎么称呼它?做我想做的事情最惯用的方式是什么?


编辑:以下是受@dunlop 回答启发的版本:

infixl 4 <&>
(<&>) :: Functor f => f a -> (a -> b) -> f b
(<&>) = flip fmap

blah =
  [1,2,3] <&>
  (+1) <&>
  (*2) >>=
  return

我还应该补充一点,我在使用bind-variant,因为我想以无点风格编写我的代码。对于do-notation,我想我不需要“假装”我正在做任何单子的事情,所以我可以使用lets。

4

2 回答 2

4

每一个Monad都是一个Functor(也是一个Applicative)。你(>>$)的是(翻转)fmap

GHCi> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
GHCi> :t (<$>) -- Infix synonym for 'fmap'
(<$>) -- Infix synonym for 'fmap'
  :: Functor f => (a -> b) -> f a -> f b
GHCi> fmap ((*2) . (+1)) [1,2,3]
[4,6,8]
GHCi> (*2) . (+1) <$> ([1,2,3] >>= \x -> [1..x])
[4,4,6,4,6,8]

(顺便说一下,翻转的通用名称fmap(<&>)。例如,镜头称之为它。)


如果您使用的是 do-notation,则几乎没有理由使用fmap显式的任何变体进行这种转换。只需将您的<-monadic 绑定切换为 let-bindings:

bazDo = do
  x <- [1,2,3]
  let y = (+1) x
      z = (*2) y
  return z
bazDo = do
  x <- [1,2,3]
  let y = (+1) x
  return ((*2) z)
于 2017-03-08T15:03:03.607 回答
1

为了更好的可读性...

这将是主观的,因为人们不同意什么是可读的。

话虽如此,我同意有时从左到右编写数据转换更容易理解。不过,我认为你>>$是矫枉过正。中的&操作员Data.Function完成这项工作:

import Data.Function

foo = [1,2,3] & fmap (+1) & fmap (*2)

我喜欢这准确地说明了从左到右的每一步要从什么开始以及要做什么。与 不同>>$的是,您不会被迫留在 monad 中:

bar = [1,2,3] & fmap (+1) & fmap (*2) & sum & negate

或者您可以预先组装您的转换并将其映射到您的 monad:

import Control.Category

f = (+1) >>> (*2)
quuz = fmap f [1,2,3]
于 2017-03-08T19:26:39.373 回答