我正在阅读“了解你是一个Haskell”之后,正在研究H-99的问题。到目前为止,我觉得我对这些概念有了很好的把握,而且我在解决或理解以前的问题方面没有太多麻烦。然而,这个让我感到困惑,我不理解解决方案。
问题是:
生成从列表的N个元素中选择的K个不同对象的组合
从12人中选出一个3人委员会的方式有多少?我们都知道存在C(12,3)= 220种可能性(C(N,K)表示众所周知的二项式系数)。对于纯数学家来说,这个结果可能很棒。但我们希望在列表中真正生成所有可能性。
提供的解决方案:
import Data.List
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = [ [] ]
combinations n xs = [ y:ys | y:xs' <- tails xs, ys <- combinations (n-1) xs']
对我而言,混淆的主要问题是y变量。根据尾部如何工作,它应该在开始时被分配整个列表,然后该列表将在生成之后预先生成。但是,当函数运行时,它返回的列表列表不会超过传入的n值。有人可以帮我理解它是如何工作的吗?
答案 0 :(得分:4)
变量y
未绑定到整个xs
列表。例如,假设xs=[1,2,3]
。然后:
y:xs' is matched against [1,2,3] ==> y=1 , xs'=[2,3]
y:xs' is matched against [2,3] ==> y=2 , xs'=[3]
y:xs' is matched against [3] ==> y=3 , xs'=[]
y:xs' is matched against [] ==> pattern match failure
请注意,y
是上面的整数,而xs'
是整数列表。
Haskell代码可以读取非确定性算法,如下所示。要从n
生成xs
元素的组合,请获取xs
的任何尾部(即,从头开始删除任意数量的元素)。如果尾部是空的,请忽略它。否则,让尾部为y:xs'
,其中y
是尾部的第一个元素,xs'
是剩余的(可能是空的)部分。取y
并将其添加到我们正在生成的组合中(作为第一个元素)。然后递归地从n-1
剩余部分中选择其他xs'
个参数,并将其添加到组合中。当n
降至零时,我们知道只有一个组合,即空组合[]
,所以请接受它。
答案 1 :(得分:0)
y
未附加到ys
。这将涉及(++) :: [a] -> [a] -> [a]
运营商。
如果您尝试追加y
和ys
,则类型不匹配。 y
的类型为a
,而ys
的类型为[a]
。
相反,y
使用ys
(cons运算符)与(:) :: a -> [a] -> [a]
进行了对比。
返回列表的长度等于n
,因为combinations
从n
递归到0
,因此它会生成n
内部列表。< / p>