9

我很难理解一个函数如何成为一个单子。

(->) r根据以下声明,函数是一个 monad Control.Monad.Instances

instance Monad ((->) r) where  
    return x = \_ -> x  
    h >>= f = \w -> f (h w) w  

甚至 Miran Lipovača所说的也让我感到困惑:

for 的实现>>=似乎有点神秘,但实际上并非如此。当我们用>>=一个单子值给一个函数时,结果总是一个单子值。所以在这种情况下,当我们将一个函数提供给另一个函数时,结果也是一个函数。这就是为什么结果以 lambda 开始的原因。>>=到目前为止,所有的实现 总是以某种方式将结果与一元值隔离,然后将函数 f 应用于该结果。同样的事情也发生在这里。要从函数中获取结果,我们必须将其应用到某物上,这就是为什么我们在(h w)这里从函数中获取结果,然后将 f 应用到该函数上的原因。f 返回一个单子值,在我们的例子中是一个函数,所以我们也将它应用到 w 上。

(>>=) 的类型签名是这样的: (>>=) :: ma -> (a -> mb) -> mb

所以我认为h它的类型是 asm afas (a -> m b)。如果一个函数是m a,它是否返回一个a类型值?还是返回其他a类型的东西?

如果将 的非单子值h馈送到f,那么我们得到: f (hw) 看起来不错。既然f是一个函数并且接受了它的唯一参数,那么它已经是一个值了,不是吗?由于它是一元函数,因此该值也是一元值。那么为什么它需要另一个值w呢?喂食不是w让它f something成为非单子的,也就是说,它不再是一个函数,不是吗?我也无法理解为什么f somethingh采用相同的参数w并返回不同的值类型(m am b)。

4

2 回答 2

12

首先,这是 的类型(>>=)

(>>=) :: (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)提供给第一个参数以获得 type 的东西a,然后将该结果和第三个参数都提供给第二个参数以获得一个类型的最终结果b

因此,((->) r)作为 aMonad表示该 monad 中每个值的额外函数参数,并且当 monadic 值组合时,单个“额外”参数被复制并赋予每个输入值。本质上,这为一元值创建了一个“只读全局环境”。Reader这种解释是作为monad明确提供的,它只是((->) r).

于 2012-10-26T03:11:24.347 回答
6

通过查看做什么可能更容易理解这个 monad join,因为 monad 可以等效地使用fmapand来定义,join而不是>>=.

的一般形式join具有 type Monad m => m (m b) -> m b,因此它采用“两层”一元值并将其分解为一层。

使用函数 monad 时,m ~ (a ->)类型join也是(a -> a -> b) -> (a -> b)如此,因此它接受一个有两个参数的函数并返回一个只接受一个参数的函数。

join :: (a -> a -> b) -> (a -> b)
join f = \x -> f x x

如您所见,它只是重复了参数。

同样,fmapon functions 只是函数组合,并且returnconst.

我认为以这种方式理解比试图理解>>=.

于 2012-10-26T03:10:24.780 回答