我很难理解函数如何成为monad。
根据(->) r
:
Control.Monad.Instances
是一个monad
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
甚至MiranLipovačasays关于它的事情让我感到困惑:
>>=
的实现似乎有点神秘,但事实并非如此 这一切。当我们使用>>=
将monadic值提供给函数时, 结果总是一个monadic值。所以在这种情况下,当我们喂一个 函数到另一个函数,结果也是一个函数。那是 为什么结果开始作为一个lambda。所有的实现>>=
到目前为止始终以某种方式将结果与monadic值隔离,然后将函数f应用于该结果。同样的事情发生了 这里。要从函数中获取结果,我们必须将其应用于 这就是为什么我们在这里(h w)
得到结果的原因 函数,然后我们应用f。 f返回一个monadic值,即 在我们的例子中是一个函数,所以我们也将它应用于w。
(>> =)的类型签名是这样的: (>> =):: m a - > (a - > m b) - > m b
因此,我认为h
的输入为m a
,f
的输入为(a -> m b)
。如果函数是m a
,它是否返回a
类型值?或者是否返回采用a
类型的其他内容?
如果h
的非monad值被输入f
,那么我们得到:
f(h w)
看起来很好。由于f
是一个函数并且已经采用了它唯一的参数,它已经是一个值,不是吗?由于它是一个monadic函数,因此该值也是monadic值。为什么它需要另一个值w
?是不是w
向f something
提供它使它成为非monadic,即它不再是一个函数,不是吗?我也无法理解为什么f something
和h
采用相同的参数w
并返回不同的值类型(m a
和m b
)。
答案 0 :(得分:11)
首先,这是(>>=)
的类型:
(>>=) :: (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”参数被复制并赋予每个输入值。从本质上讲,这为monadic值创建了一个“只读全局环境”。这种解释明确地作为Reader
monad提供,它只是((->) r)
的包装。
答案 1 :(得分:6)
通过查看join
的内容来理解这个monad可能更容易,因为monad可以使用fmap
和join
代替>>=
进行等效定义。
join
的一般形式具有类型Monad m => m (m b) -> m b
,因此它采用“双层”monadic值并将其压缩到一层。
使用monad函数m ~ (a ->)
,所以join
的类型为(a -> a -> b) -> (a -> b)
,因此它接受两个参数的函数并返回一个只需要一个函数的函数。
join :: (a -> a -> b) -> (a -> b)
join f = \x -> f x x
正如您所看到的,它只是重复了论点。
同样,函数fmap
只是函数组合,return
是const
。
我认为理解这种方式比理解>>=
要容易得多。