Haskell-选择ln函数

Haskell-选择ln函数,haskell,functional-programming,Haskell,Functional Programming,我必须编写一个函数choose ln,该函数打印所有可能组合的列表,以选择列表n元素l 例如,调用选择[1,2,3]2返回[[1,2],[1,3],[2,3]]或[[2,1],[3,1],[3,2]] 不幸的是,我不了解解决方案: choose :: [a] -> Int -> [[a]] choose _ 0 = [[]] choose [] _ = [] choose (x:xs) n = (map (\ys -> x:ys) (choose xs (n-1))) ++ (

我必须编写一个函数
choose ln
,该函数打印所有可能组合的列表,以选择列表
n
元素
l

例如,调用
选择[1,2,3]2
返回
[[1,2],[1,3],[2,3]]
[[2,1],[3,1],[3,2]]

不幸的是,我不了解解决方案:

choose :: [a] -> Int -> [[a]]
choose _ 0 = [[]]
choose [] _ = []
choose (x:xs) n = (map (\ys -> x:ys) (choose xs (n-1))) ++ (choose xs n)
我理解前两种说法。最后一行我不清楚


有人能解释一下吗?

该函数根据组合的元素列表和数量打印所有可能的组合。最后一行所做的是在给定一个非空列表和一个正整数的情况下递归地应用这个函数

首先,让我们看看这一部分:

(map (\ys -> x:ys) (choose xs (n-1)))
它使用第一个元素作为一种“常量”。它首先递归地生成其他元素的组合,然后将“constant”元素放在作为结果生成的每个列表的开头

e、 g.如果输入为[1,2,3]且需要2个元素组合,则功能将按如下方式评估:

 choose [1,2,3] 2
= choose (1:[2,3]) 2
= (map (\ys -> 1:ys) (choose [2,3] 1)) ++ (choose [2,3] 2)

choose (2:[3]) 1
= (map (\ys -> 2:ys) (choose [3] 0)) ++ (choose [3] 1)

= [[2]] ++ [[3]]
= [[2],[3]]
因为

choose 3:[] 1
= (map (\ys -> 3:ys) (choose [] 0)) ++ (choose [] 1)
= [[3]]
所以

因此

 choose (1:[2,3]) 2
= (map (\ys -> 1:ys) ([[2],[3]])) ++ (choose [2,3] 2)
= [[1,2],[1,3]] ++ (choose [2,3] 2)
上面表达式的第二部分是原始定义中的
++(选择xsn)
。它所做的只是使用原始列表中较小的子列表重复上述过程

继续上面的示例,
选择[2,3]2
计算结果为[[2,3]]


把它们放在一起,最终得到[[1,2]、[1,3]、[2,3]],这是您得到的输出。

可以通过两种方式从
x:xs
中选择
n
元素:要么选择
x
,要么不选择

如果选择了
x
,我们只需从
xs
中选择
n-1
元素。因此,我们递归地做
选择xs(n-1)
,然后在
map(\ys->x:ys)
的顶部添加
x

如果未选择
x
,我们将选择构成尾部
xs
的所有
n
元素。因此,我们考虑<代码>选择XS N< /代码> .<
最后,我们用
++

将所有这些选择放在一起,哪一部分容易混淆?您可以手工评估最后一行,还是从GHCIO的hrlp开始评估最后一行的一部分?这个实现的一个有趣之处是,如果您想得对的话,它在无限的列表上是高效的,结果是合理的<代码>选择[1,2,3],[1,2,4],[1,2,5],[1,2,6],[1,2,7],…]帕斯卡三角形!
 choose (1:[2,3]) 2
= (map (\ys -> 1:ys) ([[2],[3]])) ++ (choose [2,3] 2)
= [[1,2],[1,3]] ++ (choose [2,3] 2)