从类的名称和解析器中的用法来看,Maybe
我认为它的行为是从a <|> b <|> c
. 所以我希望输入
[] <|> [1] <|> [2, 3]
它将返回第一个非空列表,即:
[1]
但它实际上只是连接了整个事情,产生:
[1,2,3]
所以我想知道这种实现背后的原因是什么?它真的正确吗?
PS是否有任何标准功能可以满足我的期望Alternative
?
从类的名称和解析器中的用法来看,Maybe
我认为它的行为是从a <|> b <|> c
. 所以我希望输入
[] <|> [1] <|> [2, 3]
它将返回第一个非空列表,即:
[1]
但它实际上只是连接了整个事情,产生:
[1,2,3]
所以我想知道这种实现背后的原因是什么?它真的正确吗?
PS是否有任何标准功能可以满足我的期望Alternative
?
原因(嗯,一个原因)是它与MonadPlus
实例匹配。
据我所知,当一个类型同时具有 和 的实例时,这些实例匹配是可取的MonadPlus
,Alternative
因为Alternative
toApplicative
的关系类似于 to 的MonadPlus
关系Monad
。
对于你想要的行为,如果你想使用Alternative
,你需要一个newtype
列表的包装器,作为一个独立的函数,它当然也很容易定义。
[] <++ xs = xs
xs <++ _ = xs
这是预期的行为。该类Alternative
为应用函子定义了一个幺半群(因此(Applicative f) =>
定义中的类约束)。
Alternative
Applicative
与MonadPlus
has to具有相同的关系Monad
。Alternative
列表的实例给出与列表的实例相同的行为MonadPlus
(也与列表的实例相同的行为) ,这是有道理的Monoid
。
不过,这不是列表幺半群的唯一有效定义。你的定义:
instance Monoid [a] where
mempty = []
[] `mappend` xs = xs
xs `mappend` _ = xs
也满足幺半群定律(练习:检查这个!)所以你可以定义一个新类型
newtype Lst a = Lst { getLst :: [a] }
并将其制成Monoid
/ Alternative
/etc 实例,或者只是定义自己的函数来做你想做的事,如 Daniel Fischer 的回答。
Alternative 只是为应用函子定义的一个幺半群。因此,如果满足幺半群定律,则应用函子的 Alternative 实例是正确的。
我不知道是否有标准功能可以做到这一点,但您当然可以实现自己的功能或定义自己的替代实例。
您可以在typeclassopedia中阅读更多关于它们的信息。它详细解释了所有这些类型类以及它们要遵循的规律。
在实现Alternative f
(或MonadPlus f
)实例时,您必须选择一个幺半群并使用andf a
来实现它。对于某些结构,例如列表,可能存在多种可能性。列表最自然的幺半群操作是它们的连接(作为标识元素)。正如您所建议的,采用第一个非空元素也是一种可能性,但对于列表来说并不自然。您的操作几乎忽略了列表的结构(长度),它只检查列表是否为空。而且它没有添加任何新内容,因为这种幺半群运算已经可以作为的 的实例使用,它旨在表示(非)空值。empty
<|>
[]
Maybe
Alternative
这也体现在 of 的实例MonadPlus
中[]
。正如HaskellWiki上所述,对于以下情况,有两组可能的法律MonadPlus
:
[]
Maybe
统计。IO
STM
如果我们选择你的Alternative
and实现MonadPlus
,那么我们只有满足的实例... + LeftCatch
,没有满足 LeftDistribution 的实例。再一次,MonadPlus
of与of[]
没有太大区别。而且我们不会有任何东西可以让我们解决诸如send+more=money之类的问题。所以选择/ of来连接会更有趣。MonadPlus
Maybe
mplus
<|>
[]