我一直很喜欢以下有关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
中的元组构造函数,以及“形状”其他任何东西,例如构造函数之间的选择(例如Nothing
与Just
)或涉及其他类型参数的部分(例如Reader
中的环境)。
当然,仅Functor
仅限于在参数部分上映射函数。Monad
可以基于参数部分的值来创建新的“形状”,这不仅可以改变形状,还可以提供更多的功能。复制列表中的每个元素或删除前五个元素都会改变形状,但是过滤列表需要检查元素。
从本质上讲,这就是Applicative
在它们之间的适合方式-它使您可以独立地组合两个Functors
的形状和参数值,而不会让后者影响前者。
我对么?如果是这样,是否有办法向Haskell的新手表达这种微妙之处。我想用我心爱的“单子(monad)可以改变形状”这句话,让自己更诚实。如果需要的话。
也许您在这里寻找的微妙之处在于您并没有真正在“改变”任何东西。 Monad
中的任何内容都不能让您明确地弄乱形状。它可以让您根据每个参数值创建新形状,并将这些新形状重新组合为新的合成形状。
因此,您将始终受到创建形状的可用方法的限制。使用完全通用的Monad
,您所拥有的就是return
,根据定义,它可以创建任何必要的形状,从而(>>= return)
是标识函数。给定某些功能,Monad
的定义将告诉您可以做什么。它没有为您提供这些功能。
关于haskell - 与Functor不同,Monad可以改变形状吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8446263/