Haskell - 为什么要为 List 实现 Alternative

Haskell - Why is Alternative implemented for List

我已经读了一些postMeaning of Alternative(很长)

让我 post 的是对 Alternative 的总体了解。 post 很好地回答了为什么以 List.

的方式实现它

我的问题是:

是否可能有一种算法使用 Alternative 并且可能会传递一个 List 以便定义它以保持普遍性?

我认为是因为 Alternative 默认定义了 somemany,这可能是其中的一部分,但 What are some and many useful for 包含注释:

澄清一下,somemany对于最基本类型的定义,例如[]Maybe只是循环。所以somemany对他们的定义虽然有效,但是没有任何意义

在上面的“有哪些用途”link 中,Will 给出了 OP 的答案,其中可能包含我的问题的答案,但此时在我的 Haskelling 中,森林是看树有点粗

谢谢

考虑这样一个函数:

fallback :: Alternative f => a -> (a -> f b) -> (a -> f e) -> f (Either e b)
fallback x f g = (Right <$> f x) <|> (Left <$> g x)

意义不大,但您可以想象它被用在,比如说,解析器中:尝试一种方法,如果不起作用则回退到另一种方法。

这个函数在f ~ []的时候有意义吗?当然,为什么不呢。如果你认为列表的“效果”是通过一些 space 进行搜索,这个函数似乎代表了某种有偏见的选择,你更喜欢第一个选项而不是第二个选项,同时你愿意尝试要么,你也标记你去了哪条路。

像这样的函数是否可以成为某些算法的一部分,该算法在其计算的 Alternative 中是多态的?我不明白为什么不呢。 [] 有一个 Alternative 实例似乎不是不合理的,因为有一个实现满足 Alternative 法则。

关于您指出的 Will Ness 链接的答案:它涵盖了 somemany 不要 “只是循环”对于列表。他们循环非空列表。对于空列表,它们立即 return 一个值。这有多有用?可能不是很多,我必须承认。但该功能随 (<|>)empty 一起提供,这可能很有用。

在 Haskell 图书馆生态中有一个惯例,如果一个东西 可以 是 class 的一个实例,那么它 应该是class的一个实例。我怀疑对“为什么 []Alternative?”的诚实回答是“因为它可以”。

...好吧,但是为什么会有这种约定呢?简短的回答是实例是 Haskell 的一部分,它只屈服于整个程序分析。它们是全局的,如果程序的两个部分都试图进行特定的 class/type 配对,那么该冲突会阻止程序正常工作。为了解决这个问题,有一条经验法则,您编写的任何实例都应该与它关联的 class 或与其关联的类型存在于同一个模块中。

由于实例应该存在于特定的模块中,因此尽可能定义这些实例是有礼貌的——因为另一个库试图修复您没有提供实例的事实是不合理的。

Alternative 在将 [] 视为非确定性 monad 时很有用。在这种情况下,<|> 表示在两个程序之间进行选择,而 empty 表示“无有效选择”。这与例如的解释相同。解析器。

somemany 对于列表确实没有意义,因为它们尝试从第一个选项的无限列表开始贪婪地遍历给定选项中所有可能的元素列表.列表 monad 甚至还不够懒惰,因为如果给它一个空列表,它可能总是需要中止。然而,有一种情况两者都终止:当给定一个空列表时。

Prelude Control.Applicative> many []
[[]]
Prelude Control.Applicative> some []
[]

如果 somemany 被定义为懒惰的(在正则表达式意义上),这意味着他们更喜欢短列表,你会得到结果,但不是很有用,因为它首先生成只有第一个选项的所有无限数量的列表:

Prelude Control.Applicative> some' v = liftA2 (:) v (many' v); many' v = pure [] <|> some' v
Prelude Control.Applicative> take 100 . show $ (some' [1,2])
"[[1],[1,1],[1,1,1],[1,1,1,1],[1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,1,"

编辑: 我相信 somemany 函数对应于 star-semiring<|>empty 对应于半环中的加号和零号。所以在数学上(我认为),将这些操作拆分成一个单独的类型类是有意义的,但它也有点愚蠢,因为它们可以根据 Alternative.[= 中的其他运算符来实现。 26=]