我是Haskell的初学者,在完成一本书的练习后。第一个问题要求我定义一个从整数列表中删除首次出现的整数的函数。
例如
delete 5 [1,5,3,5,1]
输出:
[1,3,5,1]
第二个问题要求我创建一个函数,该函数使用我刚定义的删除函数,该函数将整数列表作为参数,并将所有排列的列表输出为列表。
例如
perms [1,2,3]
输出:
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
我尽力了,放弃了并用谷歌搜索了解决方案。
我在这里找到了:
perms [] = [[]]
perms xs = [ i:j | i <- xs, j <- perms $ delete i xs ]
[我环顾四周,发现许多其他相似的解决方案,几乎完全相同,只是使用不同的变量名和括号而不是$
符号,所以我想这是惯用的解决方案中的常见问题。
我只是有点迷茫,想准确了解这段代码在做什么。我正在通过递归逐步寻求解释,以了解此代码如何创建排列列表?
像在列表上操作的任何递归函数一样,可以将其分解为两种情况:
1)函数应该在空列表上做什么?
2)如果我知道函数在长度为n
的列表上执行的操作,我可以用它来确定函数在长度为n + 1
的列表上应该执行的操作。
[一旦您知道了这两件事,您就有了一个可以在任何列表上使用的定义(至少一个有限长度-这样的过程当然永远不会以无限长度之一结束;这在这里并不重要,因为它不会谈论无限列表中的排列没有多大意义。 [如果您具有某种数学背景,您会认为这是mathematical induction定律的简单陈述。]
对于perms
函数,很明显只有一种方法可以置换空列表的0个元素:另一种空列表。如示例解决方案的第一行所示,这为基本情况提供了[[]]
。
对于递归/归纳步骤,假设我们有一个长度为xs
(其中n
)的列表n > 0
,并假设(我们被允许)假设我们已经知道如何计算任意一个的所有排列长度n - 1
的列表。
每个排列必须从xs
的特定元素开始-让我们将此元素称为i
,并考虑如何获取第一个元素为xs
的i
的所有排列。应该清楚的是,它们与列表delete i xs
的所有排列(即删除了xs
的i
)完全对应-给定后者的排列j
,列表i : j
是排列以xs
开头的i
的整数,然后可以以这种方式获得xs
的所有此类排列。
注意,这正是列表[ i:j | j <- perms $ delete i xs ]
(顺便说一句,由于我们假设i
位于xs
中,因此delete i xs
的长度确实为n - 1
,因此通过归纳假设我们知道如何计算该长度。]
i
当然是在此处完全任意选择的-xs
的all元素将需要作为某些排列的第一个元素。因此,对于上述i
中的所有元素xs
,我们只需将以上所有内容放在一起-正是递归步骤中的表达式是:
[ i:j | i <- xs, j <- perms $ delete i xs ]
您可能需要先通读几次,然后才有道理-但这基本上是非常基本的逻辑(并且像大多数基本逻辑一样,有一个讨厌的习惯,即看起来往往比实际要复杂得多) 。
i
一个接一个地取一个元素xs
i
删除xs
并在i
之前添加到j
(perms
的xs
的每个列表元素减去i
),直到耗尽所有i
。