我一直很喜欢以下有关Monad相对于函子的力量的直观解释:Monad可以改变形状;函子不能。

例如:length $ fmap f [1,2,3]始终等于3

但是,对于monad,length $ [1,2,3] >>= g通常不等于3。例如,如果g定义为:

g :: (Num a) => a -> [a]
g x = if x==2 then [] else [x]

那么[1,2,3] >>= g等于[1,3]

稍微困扰我的是g的类型签名。用通用的monadic类型来定义改变输入形状的函数似乎是不可能的,例如:
h :: (Monad m, Num a) => a -> m a

MonadPlus或MonadZero类型类具有相关的零元素,可以代替[]来使用,但现在我们拥有的不仅仅是monad。

我对么?如果是这样,是否有办法向Haskell的新手表达这种微妙之处。我想用我心爱的“单子(monad)可以改变形状”这句话,让自己更诚实。如果需要的话。

最佳答案

我一直很喜欢以下有关Monad相对于函子的力量的直观解释:Monad可以改变形状;函子不能。

顺便说一下,您在这里缺少一些微妙之处。为了方便起见,我将在Haskell意义上将Functor分为三个部分:由类型参数确定并由fmap操作的参数部分,不变的部分,例如State中的元组构造函数,以及“形状”其他任何东西,例如构造函数之间的选择(例如NothingJust)或涉及其他类型参数的部分(例如Reader中的环境)。

当然,仅Functor仅限于在参数部分上映射函数。
Monad可以基于参数部分的值来创建新的“形状”,这不仅可以改变形状,还可以提供更多的功能。复制列表中的每个元素或删除前五个元素都会改变形状,但是过滤列表需要检查元素。

从本质上讲,这就是Applicative在它们之间的适合方式-它使您可以独立地组合两个Functors的形状和参数值,而不会让后者影响前者。

我对么?如果是这样,是否有办法向Haskell的新手表达这种微妙之处。我想用我心爱的“单子(monad)可以改变形状”这句话,让自己更诚实。如果需要的话。

也许您在这里寻找的微妙之处在于您并没有真正在“改变”任何东西。 Monad中的任何内容都不能让您明确地弄乱形状。它可以让您根据每个参数值创建新形状,并将这些新形状重新组合为新的合成形状。

因此,您将始终受到创建形状的可用方法的限制。使用完全通用的Monad,您所拥有的就是return,根据定义,它可以创建任何必要的形状,从而(>>= return)是标识函数。给定某些功能,Monad的定义将告诉您可以做什么。它没有为您提供这些功能。

关于haskell - 与Functor不同,Monad可以改变形状吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8446263/

10-12 01:36
查看更多