我很难理解一个函数如何成为一个 monad。
根据 Control.Monad.Instances
中的声明,函数 (->) r
是一个 monad:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
甚至米兰·利波瓦卡 (Miran Lipovača) says这让我很困惑:
The implementation for
>>=
seems a bit cryptic, but it's really not all that. When we use>>=
to feed a monadic value to a function, the result is always a monadic value. So in this case, when we feed a function to another function, the result is a function as well. That's why the result starts off as a lambda. All of the implementations of>>=
so far always somehow isolated the result from the monadic value and then applied the function f to that result. The same thing happens here. To get the result from a function, we have to apply it to something, which is why we do(h w)
here to get the result from the function and then we apply f to that. f returns a monadic value, which is a function in our case, so we apply it to w as well.
(>>=) 的类型签名是这样的: (>>=)::m a -> (a -> m b) -> m b
因此,我认为 h
的类型为 m a
,f
的类型为 (a -> m b)
。如果函数是 m a
,它是否返回 a
类型值?或者它是否返回采用 a
类型的其他内容?
如果将 h
的非 monad 值输入到 f
,那么我们得到:
f(高宽)
看起来不错。由于 f
是一个函数并且采用了唯一的参数,因此它已经是一个值,不是吗?由于它是一个单子(monad)函数,因此该值也是一个单子(monad)值。那么为什么它需要另一个值w
?将 w
提供给 f some
不会使其成为非单子(monad),即它不再是一个函数,不是吗?我也无法理解为什么 f Something
和 h
采用相同的参数 w
并返回不同的值类型(m a
和m b
)。
最佳答案
首先,这是 (>>=)
的类型:
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
现在,将 m
专门用于 ((->) r)
:
(>>=) :: ((->) r) a -> (a -> ((->) r) b) -> ((->) r) b
用所有函数箭头中缀重写:
(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)
删除一些多余的括号:
(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b
此时应该更容易看到发生了什么:将第三个参数(r
类型)赋予第一个参数以获取 a
类型的内容>,然后将该结果和第三个参数都赋予第二个参数,以获得 b
类型的最终结果。
因此,((->) r)
作为 Monad
表示该 monad 中每个值的额外函数参数,并且当 Monadic 值组合在一起时,单个“extra"参数被复制并赋予每个输入值。本质上,这为一元值创建了一个“只读全局环境”。此解释作为 Reader
monad 明确提供,它只是 ((->) r)
的包装器。
关于haskell - 作为 Monad 实例的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13080014/