我想弄清楚99 Haskell problems问题26的解决方案之一是如何工作的。解决方案如下:
combination :: Int -> [a] -> [[a]]
combination 0 _ = [ [] ]
combination i xs = [ y:ys | y:xs' <- tails xs, ys <- combination (i-1) xs']
我无法理解如何有多个列表具有相同的头部。对我来说,y
中使用y:ys
生成的tails xs
部分只能用于撰写一个列表。
示例:
combination 2 [1,2,3]
首先,我们从y
获取tails xs
部分,它为我们提供了三个列表:[1,(not known yet)]
,[2,(not known yet)]
,[3,(not known yet)]
。那么最后我们得到多个结果以1作为头部?
我也无法理解为什么列表[3]
不会出现在结果中?它肯定会出现在tails xs
生成的一个列表中。我不想在一个单独的问题中提出这个问题 - 我希望这很好。
答案 0 :(得分:3)
列表推导以某种方式定义嵌套循环。因此,在定义中
combinations n xs =
我们可以阅读代码
[ y:ys | y:t <- tails xs, ys <- combinations (n-1) t]
作为
for each (y:t) in (tails xs)
for each ys in (combinations (n-1) t)
produce (y:ys) as a new element of the resulting list
换句话说,从列表中选择n
元素意味着选择一些元素,并在列表中选择n-1
个元素。
此定义的非确定性特征通过生成所有可能解决方案的列表来表示。我们只选择元素的n-1
元素到,只在排列下生成 unique 的解决方案。
我们以xs = [1,2,3]
为例。 tails [1,2,3]
产生什么?
当然是[[1,2,3], [2,3], [3], []]
。现在,这相当于
[ r | r <- [[1,2,3], [2,3], [3], []] ]
这意味着,从该列表中抽取r
,连续地获取其元素的值。 r
是无可辩驳的模式; (y:t)
是一种可反驳的模式,即它将无法匹配[]
元素:
[ (y,t) | (y:t) <- tails [1,2,3]]
=> [(1,[2,3]), (2,[3]), (3,[])]
所以你看,t
不是&#34;还不知道&#34; 。 已知,它只是给定列表的尾部。当y
与3匹配时,t
与[]
匹配。
此外,
[ (y,q) | (y:t) <- tails [1,2,3], q <- [10,20]]
=> [(1,10), (1,20), (2,10), (2,20), (3,10), (3,20)]
这很有说服力,希望清除您的第一个问题:对于每个匹配的(y:t)
模式,q
都是从[10,20]
中提取的,即它也会采用列表中的值(此处为[10,20]
),对于每个y
连续,就像在嵌套循环中一样。
对于combinations 2 [1,2,3]
我们的例子
combinations 2 [1,2,3]
=
for each (y,t) in [ (1,[2,3]), (2,[3]), (3,[]) ]
for each ys in (combinations 1 t)
produce (y:ys)
=
for y = 1, t = [2,3]
for each ys in (combinations 1 [2,3]) produce (1:ys) , and then
for y = 2, t = [3]
for each ys in (combinations 1 [3]) produce (2:ys) , and then
for y = 3, t = []
for each ys in (combinations 1 []) produce (3:ys)
combinations 1 []
为[]
,因为tails []
为[[]]
,模式匹配(y:t)
与[]
作为生成器(y:t) <- [[]]
的一部分将失败;因此第三个 for
行(在解决方案的头部会有3
)不会产生任何解决方案 - 因为没有其他元素可供使用它有权选择第二个元素,因为我们需要总共选择2个元素; 3确实参与其他解决方案的尾部,因为它应该如此)。
第二个 for
行显然只生成一个解决方案[2,3]
。第一个 for
行会产生什么?
for each ys in (combinations 1 [2,3]) produce (1:ys)
combinations 1
只占用一个元素,因此会产生[2]
和[3]
;因此,第一个for
行生成两个解,[1,2]
和[1,3]
。或者更详细地说,
combinations 1 [2,3]
=
for y = 2, t = [3]
for each ys in (combinations 0 [3]) produce (2:ys) , and then
for y = 3, t = []
for each ys in (combinations 0 []) produce (3:ys)
和combinations 0
总是生成一个空列表的单个解决方案(单个列表,其中列表为空唯一元素[ [] ]
,表示从列表中选取0个元素的解决方案)。
总的来说,返回了三个解决方案的列表[[1,2], [1,3], [2,3]]
。
答案 1 :(得分:2)
这里要注意的核心问题是问题的递归性。
我们如何从列表中选择i
个项目?
i-1
个项目i
个项目这样做的:
[ y:ys | y:xs' <- tails xs, ys <- combination (i-1) xs']
xs
的所有尾巴,即查看为i
组合选择 first 元素的所有可能性 i-1
项,因此,我们需要将该元素连接到i-1
项与其余项的组合。