标准库的Haskell类型类MonadPlus
,Alternative
以及Monoid
各自提供两种方法具有基本相同的语义:
mzero
,empty
或mempty
.a -> a -> a
,在类型类联接值加在一起:mplus
,<|>
或mappend
.所有这三个都规定了应遵守的法律:
mempty `mappend` x = x
x `mappend` mempty = x
Run Code Online (Sandbox Code Playgroud)
因此,似乎三个类型都提供相同的方法.
(Alternative
也提供some
和many
,但它们的默认定义通常是足够的,所以它们在这个问题上并不太重要.)
所以,我的疑问是:为什么这三个极为相似的类?除了不同的超类限制之外,它们之间是否有任何真正的区别?
haskell functional-programming typeclass applicative monoids
我一直在浏览Typeclassopedia来学习类型类.我不理解Alternative
(MonadPlus
就此而言).
我遇到的问题:
'pedia说"替代类型类适用于具有幺半群结构的Applicative仿函数." 我不明白 - 不是替代意味着与Monoid完全不同的东西吗?也就是说,我理解了替代类型类在两件事之间的选择,而我理解Monoids是关于组合事物.
为什么Alternative需要一个empty
方法/成员?我可能错了,但似乎根本没有使用...至少在我能找到的代码中.它似乎不符合课堂主题 - 如果我有两件事,需要选择一件,我需要什么'空'?
为什么Alternative类需要一个Applicative约束,为什么它需要一种* -> *
?为什么不<|> :: a -> a -> a
呢?所有的实例仍然可以用同样的方式实现......我想(不确定).Monoid没有提供什么价值?
什么是点MonadPlus
式类?我不能解开所有善良的通过只是使用的东西既是Monad
和Alternative
?为什么不放弃呢?(我确定我错了,但我没有任何反例)
希望所有这些问题都是连贯的......!
赏金更新:@Antal的答案是一个很好的开始,但Q3仍然是开放的:替代品提供的Monoid不是什么?我发现这个答案不能令人满意,因为它缺乏具体的例子,并且特别讨论了Alternative的高知名度如何将它与Monoid区分开来.
如果要将应用效果与Monoid的行为结合起来,为什么不只是:
liftA2 mappend
Run Code Online (Sandbox Code Playgroud)
这对我来说更加令人困惑,因为许多Monoid实例与Alternative实例完全相同.
这就是为什么我要寻找具体的例子,说明为什么备选是必要的,以及它与Monoid的不同之处 - 或者意味着不同的东西.
有一个实例Monoid a => Monoid (Const a b)
为Const
从仿函数Control.Applicative
.还有一个例子Monoid m => Applicative (Const m)
.
因此,我希望还有一个实例Monoid m => Alternative (Const m)
与之相符Monoid
.这只是一个应该修复的遗漏,还是有更深层次的原因?
我目前正在读关于另类/ MonadPlus类型类维基教科书.它很好地描述了这种差异.然而,一个令人费解的部分是guard
我假设的函数用于"短路"计算.(我对吗?)
guard
虽然定义的函数Control.Monad
有一个Alternative
约束,如下(链接).
guard :: (Alternative f) => Bool -> f ()
guard True = pure ()
guard False = empty
Run Code Online (Sandbox Code Playgroud)
但是上面的文章提到只MonadPlus
需要强制执行左零和零零定律(因此更强的主张).
mzero >>= f = mzero -- left zero
m >> mzero = mzero -- right zero
Run Code Online (Sandbox Code Playgroud)
鉴于guard
函数的目的,不应该用MonadPlus
约束来定义它吗?如果guard
应该"短路"计算,我们不需要更强的定律吗?我很好奇特定设计选择背后的原因.
ps:我不知道什么是比"短路"这个词更好的描述"取消前期计算"行为的方法?
我知道有些人认为fail
是个错误,我明白为什么.(似乎MonadPlus是为了取代它).但只要它存在,似乎使用部分函数fail
而pure
不是Just
和Nothing
.因为这将允许你做你现在可以做的所有事情和更多,所以像safeHead
你可以给你传统的Just
/ Nothing
或者你可以返回[x]
/ []
.
从我所读到的内容MonadPlus
看起来似乎比使用更好fail
.但是我对此肯定不够了解,而且它也可能涉及拉入Prelude,这可能是一个好主意,但这将是一个比使用更大的变化fail
.
所以我想我的问题是为什么部分函数不使用fail
OR MonadPlus
,两者似乎都比使用具体类型更好.