从类的名称和解析器中的用法以及Maybe
我认为它的行为是从a <|> b <|> c
中选择第一个非空输入。所以我期望输入
[] <|> [1] <|> [2, 3]
它将返回第一个非空列表,即:
[1]
但它实际上只是整合了整个事情,产生:
[1,2,3]
所以我想知道这种实施背后的原因是什么?它确实是正确的吗?
P.S。是否有任何标准功能能够满足我对Alternative
的预期效果?
答案 0 :(得分:4)
原因(嗯,一个原因)是它与MonadPlus
实例匹配。
据我所知,当一个类型同时具有MonadPlus
和Alternative
的实例时,这些实例是匹配的,因为Alternative
与{{Applicative
的关系1}}就像MonadPlus
与Monad
的关系。
对于您想要的行为,如果您想使用Alternative
,您需要一个newtype
包装列表,作为一个独立的功能,它当然也很容易定义。
[] <++ xs = xs
xs <++ _ = xs
答案 1 :(得分:4)
这是预期的行为。 Alternative
类为applicative functor定义了一个monoid(因此定义中的(Applicative f) =>
类约束)。
Alternative
与Applicative
的关联与MonadPlus
与Monad
的关系相同。有意义的是,列表的Alternative
实例提供与列表的MonadPlus
实例相同的行为(以及与列表的Monoid
实例相同的行为)。
这不是列表monoid的唯一有效定义。你的定义:
instance Monoid [a] where
mempty = []
[] `mappend` xs = xs
xs `mappend` _ = xs
也满足了幺半群定律(练习:检查这个!)所以你可以定义一个新类型
newtype Lst a = Lst { getLst :: [a] }
并将其转换为Monoid
/ Alternative
/ etc实例,或者只是定义自己的函数来执行您想要的操作,就像Daniel Fischer的回答一样。
答案 2 :(得分:3)
替代方案只是为应用函子定义的幺半群。因此,如果它适用于幺半群定律,那么应用仿函数的替代实例是正确的。
我不知道是否有标准功能可以做到这一点,但您可以实现自己的功能或定义自己的替代实例。
您可以在typeclassopedia中详细了解它们。这将详细解释所有这些类型以及它们应遵循的法则。
答案 3 :(得分:2)
在实施Alternative f
(或MonadPlus f
)实例时,您必须选择f a
上的幺半群,并使用empty
和<|>
实施。对于某些结构,例如列表,可能存在多种可能性。列表最自然的单一运算是它们的串联([]
是标识元素)。如您所述,采用第一个非空元素也是一种可能性,但对于列表而言并不自然。您的操作几乎忽略了列表的结构(长度),它只检查列表是否为空。并且它不会添加任何新内容,因为这种幺半群操作已经可以作为Maybe
的{{1}}实例使用,该实例用于表示(非)空值。
这也反映在Alternative
MonadPlus
的实例中。正如HaskellWiki所述,[]
的实例有两套可能的法律:
MonadPlus
[]
,Maybe
和IO
确认。如果我们选择了STM
和Alternative
的实施,那么我们只有满足MonadPlus
的实例,没有令人满意的LeftDistribution。同样,... + LeftCatch
的{{1}}与MonadPlus
的{{1}}差别不大。而且我们没有任何东西可以让我们解决像send+more=money puzzle这样的问题。因此,选择要[]
的{{1}} / MonadPlus
进行连接会更有趣。