定义 Monad 运算符

Defining Monad Operators

在 Haskell 的 Monad 中,我可以轻松地将运算符 (>=>) 定义为:

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \x -> f x >>= g

我也知道 (>>=) 可以用 (>=>) 表示:让我们称 (>>=)(..):

(..) :: Monad m => m a -> (a -> m b) -> m b
m .. k = m >=> \_ -> k

但是有些地方不对...有人能指出什么吗?

使用常量函数(即 \_ -> -- etc.)从不是函数的参数中创建函数以便将其传递给 (>=>) 的想法是合理的.只有两个问题。首先,你这样做是为了错误的论点,因为不是函数的论点是 m:

GHCi> :t \m k -> (\_ -> m) >=> k
\m k -> (\_ -> m) >=> k :: Monad m => m b -> (b -> m c) -> a -> m c

其次,(>=>) 为您提供了一个函数(在上面的演示中属于 a -> m c 类型)。您必须将它应用于某些东西才能获得与 (>>=) 之一匹配的结果类型。由于该参数无关紧要(您最终将其提供给常量函数),您可以只使用 ():

GHCi> :t \m k -> ((\_ -> m) >=> k) ()
\m k -> ((\_ -> m) >=> k) () :: Monad m => m b -> (b -> m c) -> m c

就是这样。我发现使用 const 函数比写 \_ -> 稍微漂亮一点,所以我会把它写成:

(>>..) :: Monad m => m a -> (a -> m b) -> m b
m >>.. k = (const m >=> k) ()

解决方法如下:

(..) :: Monad m => m a -> (a -> m b) -> m b
m .. k =
  (const m >=> k) undefined

我们使用 constm a 类型的操作提升到 whatever -> m a。这个提升版本不在乎我们传递给它的东西,所以它也可能是 undefined.