我一直很喜欢以下关于单子相对于函子的力量的直观解释:单子可以改变形状;函子不能。
例如:length $ fmap f [1,2,3]
总是等于3
.
然而,对于单子来说,length $ [1,2,3] >>= g
往往不等于3
。例如,如果g
定义为:
g :: (Num a) => a -> [a]
g x = if x==2 then [] else [x]
then [1,2,3] >>= g
等于[1,3]
.
让我有点困扰的是类型签名g
。使用通用的一元类型来定义一个改变输入形状的函数似乎是不可能的,例如:
h :: (Monad m, Num a) => a -> m a
MonadPlus 或 MonadZero 类型类具有相关的零元素,可以使用而不是[]
,但现在我们拥有的不仅仅是一个单子。
我对么?如果是这样,有没有办法向 Haskell 新手表达这种微妙之处。我想让我心爱的“单子可以改变形状”这句话变得更诚实一些;如果需要的话。