为什么备用连接列表而不是选择第一个非空列表?

时间:2013-01-07 12:32:05

标签: haskell

从类的名称和解析器中的用法以及Maybe我认为它的行为是从a <|> b <|> c中选择第一个非空输入。所以我期望输入

[] <|> [1] <|> [2, 3]

它将返回第一个非空列表,即:

[1]

但它实际上只是整合了整个事情,产生:

[1,2,3]

所以我想知道这种实施背后的原因是什么?它确实是正确的吗?

http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Applicative.html#t:Alternative

P.S。是否有任何标准功能能够满足我对Alternative的预期效果?

4 个答案:

答案 0 :(得分:4)

原因(嗯,一个原因)是它与MonadPlus实例匹配。

据我所知,当一个类型同时具有MonadPlusAlternative的实例时,这些实例是匹配的,因为Alternative与{{Applicative的关系1}}就像MonadPlusMonad的关系。

对于您想要的行为,如果您想使用Alternative,您需要一个newtype包装列表,作为一个独立的功能,它当然也很容易定义。

[] <++ xs = xs
xs <++ _  = xs

答案 1 :(得分:4)

这是预期的行为。 Alternative类为applicative functor定义了一个monoid(因此定义中的(Applicative f) =>类约束)。

AlternativeApplicative的关联与MonadPlusMonad的关系相同。有意义的是,列表的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所述,[]的实例有两套可能的法律:

  • Monoid + LeftZero + LeftDistribution - 由MonadPlus
  • 确认
  • Monoid + LeftZero + LeftCatch - 由[]MaybeIO确认。

如果我们选择了STMAlternative的实施,那么我们只有满足MonadPlus的实例,没有令人满意的LeftDistribution。同样,... + LeftCatch的{​​{1}}与MonadPlus的{​​{1}}差别不大。而且我们没有任何东西可以让我们解决像send+more=money puzzle这样的问题。因此,选择要[]的{​​{1}} / MonadPlus进行连接会更有趣。