我一直在浏览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的不同之处 - 或者意味着不同的东西.
在他的回答这个问题"类型类之间的区别MonadPlus
,Alternative
以及Monoid
?",爱德华Kmett说,
而且,即使
Applicative
是超级课程Monad
,你最终还是需要MonadPlus
上课,因为顺从Run Code Online (Sandbox Code Playgroud)empty <*> m = empty
并不足以证明这一点
Run Code Online (Sandbox Code Playgroud)empty >>= f = empty
因此声称某事物是一件事,
MonadPlus
比宣称事情要强Alternative
.
很明显,任何适用函子是不是一个单子是自动的一个例子Alternative
是不是MonadPlus
,但爱德华Kmett的回答意味着存在一个单子这是一个Alternative
,但不是一个MonadPlus
:它empty
和<|>
将满足Alternative
法律,1而不是MonadPlus
法律.2 我自己无法想出这样的例子; 有人知道吗?
1我无法找到一套规则的规范参考Alternative
,但是我将我认为它们的内容大概放在我对" 类型类的含义及其与其他类型的关系的混淆"这一问题的答案的中间.类"(搜索短语"正确的分配").我认为应该遵守的四项法律是:Alternative
<*>
: (f …
该哈斯克尔维基断言
MonadPlus的实例需要满足几个规则,就像Monad的实例需要满足三个monad定律一样.......最重要的是mzero和mplus形成一个幺半群.
其结果是mplus
必须是联想的.该哈斯克尔维基同意.
然而,Oleg在他的众多回溯搜索实现之一中写道
-- Generally speaking, mplus is not associative. It better not be,
-- since associative and non-commutative mplus makes the search
-- strategy incomplete.
Run Code Online (Sandbox Code Playgroud)
定义非关联是否是犹太教mplus
?MonadPlus
如果mplus
不是关联的话,前两个链接非常清楚地表明你没有真实的实例.但是,如果奥列格确实它...(在另一方面,在该文件中,他只是定义调用的函数mplus
,而并没有说这 mplus
是mplus
的MonadPlus
,他选择了一个非常令人迷惑的名字,如果这是正确的解释.)
Haskell提供了一个标准类型类"替代",它有效地<|>
为任何类型的应用程序提供操作符.
正如我所理解的那样,Alternative被认为是一个关于Applicative的Monoid,但是<|>
运算符似乎在许多不是Applicative Functors的类型中都是完全有意义的,并且不需要对Applicative类类的任何特定依赖它工作正常.
是否有一个理由为什么Alternative需要成为Applicative的子类,如果有的话,是否有一个标准的类型类来定义非应用类型的类似功能?
现在有几次,我发现自己定义了:
(<?>) :: [a] -> [a] -> [a]
[] <?> ys = ys
xs <?> _ = xs
Run Code Online (Sandbox Code Playgroud)
当然,这是一个关联操作,空列表[]
既是左标识又是右标识。它的功能类似于 Python 的or
.
在我看来,这会是一个很好的(<|>)
,比原来更好的(++)
。选择第一个非空列表感觉更像是我对命名类型类的期望,Alternative
而不是连接列表。诚然,它不太合适MonadPlus
,但我认为为救赎付出的代价很小。我们已经在标准库中拥有(++)
和;(<>)
我们是否需要另一个同义词,或者一个新函数(据我所知)会更有帮助吗?
我起初认为这可能是一个很好的Alternative
例子,但在相关问题的答案ZipList
之后的讨论让我相信了事实并非如此。除了向后兼容性和保持明智之外,当前实例而不是这个新实例还有什么理由呢?MonadPlus
从类的名称和解析器中的用法来看,Maybe
我认为它的行为是从 中选择第一个非空输入a <|> b <|> c
。所以我期望输入
[] <|> [1] <|> [2, 3]
Run Code Online (Sandbox Code Playgroud)
它将返回第一个非空列表,即:
[1]
Run Code Online (Sandbox Code Playgroud)
但它实际上只是连接了整个事情,产生:
[1,2,3]
Run Code Online (Sandbox Code Playgroud)
所以我想知道这样的实施背后的原因是什么?它实际上是正确的吗?
PS 是否有任何标准功能可以达到我的预期Alternative
?
我可能一直错误地认为 Haskell 比现在更懒惰,但我想知道是否有办法两全其美……
Data.Monoid
并Data.Semigroup
定义 的两个变体First
。幺半群版本对最左边的非空值建模,而半群版本只是对最左边的值建模。
这适用于纯值,但考虑不纯值:
x = putStrLn "x" >> return 42
y = putStrLn "y" >> return 1337
Run Code Online (Sandbox Code Playgroud)
这两个值都具有类型Num a => IO a
。IO a
是一个Semigroup
实例,当a
是:
instance Semigroup a => Semigroup (IO a)
-- Defined in `Data.Orphans'
Run Code Online (Sandbox Code Playgroud)
这意味着可以组合两个IO (First a)
值:
Prelude Data.Semigroup Data.Orphans> fmap First x <> fmap First y
x
y
First {getFirst = 42}
Run Code Online (Sandbox Code Playgroud)
我们可以看到,虽然双方x
并y
产生各自的副作用,即使y
是从来没有要求。
这同样适用于Data.Monoid …
假设我正在创建一个可以抛出错误的简单解释器,例如
type Error = String
data Term = Con Int | Div Term Term
eval :: (MonadError Error m) => Term -> m Int
eval (Con a) = return a
eval (Div u v) = do
a <- eval u
b <- eval v
if b == 0 then
throwError "Division by zero"
else
return $ a `div` b
Run Code Online (Sandbox Code Playgroud)
具体错误处理程序的典型选择是Either Error
.
runEval :: Term -> Either Error Int
runEval = eval
Run Code Online (Sandbox Code Playgroud)
现在假设我想扩展这个解释器来处理非确定性。例如,我可以添加一个Choice Term Term
可以评估其第一个或第二个参数的术语。
data Term …
Run Code Online (Sandbox Code Playgroud) 我承认这个问题有点不明确,但我想知道为什么我从来没有偶然发现Haskell中的仿函数上的monoids类型类.我是否错过了它,是否有充分的理由要求这种缺席,还是完全归因于历史原因?恕我直言,下面的继承图表看起来有点奇怪没有右上角:
Functor
|
V
Applicative ––> Alternative
| |
V V
Monad ––> MonadPlus
Run Code Online (Sandbox Code Playgroud)