初学者怀疑List Comprehension Haskell

时间:2017-08-30 03:10:51

标签: list haskell list-comprehension

我目前正在处理Wiki上的 99 Haskell问题。话虽如此,我正在做问题编号 26 ,这需要一个程序,可以在给定的集合中写入与 n 元素的所有组合。我用大量的功能完成了我的实现,程序似乎是正确的。但我的问题不是来自于此,而是来自Haskell Wiki的其中一个解决方案

Selenium::WebDriver::Error::WebDriverError: unable to connect to chromedriver 127.0.0.1:9516

我了解combinations :: Int -> [a] -> [[a]] combinations 0 _ = [ [] ] combinations n xs = [ y:ys | y:xs' <- tails xs , ys <- combinations (n-1) xs'] 已针对函数 y:xs 提供的每个列表进行解析,从而生成可能值的列表,但我无法理解tails值为ys,以便y:ys为我提供所有正确的解决方案。

另一个更重要的问题是为什么这两个表达式会产生不同的结果?

[xs | y:xs <- tails [1,2,3]]
[[2,3],[3],[]]

[xs | y:xs <- tails [1,2,3], z <- xs]
[[2,3],[2,3],[3]]

它们可能没有任何实际用途,但它们向我展示了一个Haskell初学者,这是一种非常奇怪的行为。为什么应用z <- xs会更改xs的值?

2 个答案:

答案 0 :(得分:3)

由于comprehension desugaring rules,它们的结果不同。如果我们有

[ expression | a <- as, b <- bs ]

然后我们会得到

concatMap (\a -> concatMap (\b -> [expression]) bs) as

即使b中未使用expression,我们仍然会有更多元素。例如,concatMap (const [1]) [1..10]将导致replicate 10 1。因此,如果您在理解中添加另一个列表,则更改concatMap的数量,因此也更改输出的数量(除非列表中只包含一个元素):

[a | a <- [1..10]]             -- results in [1..10]
[a | a <- [1..10], _ <- [1,2]] -- results in [1,1,2,2,3,3,4,4,...,9,9,10,10]
[a | _ <- [1,2], a <- [1..10]] -- results in [1..10] ++ [1..10]

答案 1 :(得分:2)

代码

combinations n xs = [ y:ys | y:xs' <- tails xs
                           , ys <- combinations (n-1) xs']

读作:从n选择xs个元素,选择y中的任意xs,并将y之后的元素尾部命名为{ {1}}。然后递归选择xs'中的n-1元素,命名任何此类选项xs'。结果由可以以这种方式生成的所有ys形成。

说服自己这个算法确实采取了所有可能的选择(确切地说:所有选择都遵循原始列表y:ys给出的排序)。

请注意一些正确处理的极端情况。 首先,在xs内,我们还会找到空尾tails xs,但这会被忽略,因为它不是[]形式。 然后,尾部y:xs'可能比xs'元素短。在这种情况下,n-1会找到ys <- combinations (n-1) xs'的零选项,因此没有&#34;输出&#34;将为此ys生成。

最后,关于你的最后一个问题。考虑这个例子:

xs'

[ 42 | x <- [1,2,3 ] ] == [ 42, 42, 42 ] 的值不会影响x的值,因为42是常量,但它会影响其多样性。这与命令行循环42非常相似,它会多次产生输出。