Haskell 排列库函数 - 请澄清一下?

标签 haskell recursion closures permutation

这是 Haskell 的 Data.List 模块中 permutations 函数的代码:

permutations            :: [a] -> [[a]]
permutations xs0        =  xs0 : perms xs0 []
  where
    perms []     _  = []
    perms (t:ts) is = foldr interleave (perms ts (t:is)) (permutations is)
      where interleave    xs     r = let (_,zs) = interleave' id xs r in zs
            interleave' _ []     r = (ts, r)
            interleave' f (y:ys) r = let (us,zs) = interleave' (f . (y:)) ys r
                                     in  (y:us, f (t:y:us) : zs)

有人可以花时间向我解释一下这段代码是如何工作的吗?

我的困惑源于这样一个事实:我非常习惯编写没有外部依赖项的函数(即使它们嵌套在另一个函数中),特别是如果它们是递归的。 perms 内存在 permutations 以及 interleave' 内存在 tts >,就功能流程而言,我迷失了。

谢谢!

最佳答案

首先,我将以一种对您来说可能更容易的形式重写代码 理解,内部函数定义移到主函数之外。请注意,我必须向 interleave 添加一些参数,并且 interleave' 以便他们可以“看到”他们拥有的所有相同变量 当它们在其他函数中定义时访问。

为了清楚起见,我还添加了类型签名。

permutations :: [a] -> [[a]]
permutations xs0 =  xs0 : perms xs0 []

函数perms采用两个列表,并创建每个可能的列表 两个列表中元素的排列 - 但不包括原始顺序。例如:

λ> perms "ab" "XY"
["aXYb","XaYb","aYXb","YaXb","baXY","abXY","aXbY","bXaY","XbaY","XabY","bYXa","YbXa","YXba","bXYa","XbYa","XYba","bYaX","YbaX","YabX","baYX","abYX","aYbX"]

因此,当我们使用第二个空列表调用它时,如permutations 所做的那样,它会为我们提供输入元素的所有其他可能的排列。我们所要做的就是附加原来的序列,然后我们就得到了答案。 (如果您查看上面的排列,您就会发现这正是它的作用。)

λ> perms "abc" ""
["bac","cba","bca","cab","acb"]

这是定义或权限

perms :: [a] -> [a] -> [[a]]
perms []     _  = []
perms (t:ts) is = foldr (interleave (t:ts)) (perms ts (t:is)) (permutations is)

函数interleave采用两个列表,并生成每个可能的列表 将它们洗在一起的方法(就像洗一副牌一样)。那么它 将第三个列表附加到可能的随机播放列表中。例如:

λ> interleave "ab" "XY" ["@", "#"]
["aXYb","XaYb","@","#"]

这是它的定义:

interleave :: [t] -> [t] -> [[t]] -> [[t]]
interleave (t:ts) xs r  = let (_,zs) = interleave' (t:ts) id xs r in zs

interleave' :: [t] -> ([t] -> a) -> [t] -> [a] -> ([t], [a])
interleave' (_:ts) _ []     r = (ts, r)
interleave' (t:ts) f (y:ys) r  = let (us,zs) = interleave' (t:ts) (f . (y:)) ys r
                                     in  (y:us, f (t:y:us) : zs)

关于Haskell 排列库函数 - 请澄清一下?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17301022/

相关文章:

javascript - 谷歌闭包编译器javascript解析错误

c# - 如何在 XAML 中具有递归或层次结构列表和子列表?

javascript - 递归字符串解析为对象

javascript - JavaScript 中的调用堆栈变量

php - 带有匿名函数和闭包的 cURL WRITEFUNCTION 回调

json - 创建没有组合器模式的递归 JSON 写入

haskell - Haskell 上有 getInt 函数吗?

haskell - 在 Haskell 中构建(惰性)映射的有效方法

Haskell - 如何转换 map 总和( map (x :) xss) to map (x+) (map sum xss)

haskell - 术语 : What does it mean to 'instantiate type variables' in Prof. Giesl 的 Haskell 讲座