作为Monad实例的功能

时间:2012-10-26 02:37:17

标签: haskell monads

我很难理解函数如何成为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 af的输入为(a -> m b)。如果函数是m a,它是否返回a类型值?或者是否返回采用a类型的其他内容?

如果h的非monad值被输入f,那么我们得到:         f(h w) 看起来很好。由于f是一个函数并且已经采用了它唯一的参数,它已经是一个值,不是吗?由于它是一个monadic函数,因此该值也是monadic值。为什么它需要另一个值w?是不是wf something提供它使它成为非monadic,即它不再是一个函数,不是吗?我也无法理解为什么f somethingh采用相同的参数w并返回不同的值类型(m am b)。

2 个答案:

答案 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可以使用fmapjoin代替>>=进行等效定义。

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只是函数组合,returnconst

我认为理解这种方式比理解>>=要容易得多。