【问题标题】:What direction is the fold procedure in MIT Scheme?MIT 方案中的折叠过程是什么方向?
【发布时间】:2020-09-10 21:51:37
【问题描述】:

如果我想在 MIT Scheme 中反转一个列表,我可以使用(fold cons '() list) 来实现,这样如果列表是(define lis '(1 2 3 4)),那么(fold cons '() lis) 会给出(4 3 2 1)。有两种折叠,左右折叠,但如果我使用(fold-right cons '() lis),我会得到(1 2 3 4),所以普通折叠不能是那种。另外,如果我使用(fold-left cons '() lis),我会得到((((() . 1) . 2) . 3) . 4),这样在原始示例中也不能折叠。反转列表需要什么样的折叠?

我问是因为我希望能够进行通用折叠:

(define ls '((1 2 3) (4 5 6)))
(gen-fold cons '() ls)
=> ((6 5 4) (3 2 1))
(define l2 '(((1 2) (2 3)) ((3 4) (4 5))))
(gen-fold cons '() ls)
=> (((5 4) (4 3)) ((3 2) (2 1)))

编辑:为了更好地呈现问题,这些图表描述了我认为在调用 '(fold cons '() '(1 2 3)) 时会发生的列表轮换,假设 fold 是修改后的 fold-left 根据 Alexis king:

(定义 lis (list '(1 2 3)) 缺点 / \ 1个缺点 / \ 2个缺点 / \ 3'() (缺点 '()) 缺点 / \ 缺点'() / \ 1个缺点 / \ 2个缺点 / \ 3'() (向左折叠 (cons lis '())) 缺点 / \ 缺点 / \ / \ 2个缺点1'() / \ 3'() 缺点 / \ 缺点 / \ / \ 3 '() 2 个缺点 / \ 1'() 缺点 / \ 3个缺点 / \ 2个缺点 / \ 1'()

【问题讨论】:

  • 基础 MIT Scheme 环境不包含 fold 函数,仅包含 fold-leftfold-right。我能想到的唯一半内置fold 来自SRFI-1。您是否包含任何会引入 fold 定义的内容?
  • 看起来它是一个内置的,因为通过全新安装 mit-scheme 我可以进入并输入 (fold cons '() '(1 2 3)) 并得到 => (3 2 1) 而无需定义折叠
  • “反转列表需要什么样的折叠?” 左折叠 {cons 参数顺序颠倒}。

标签: scheme reduce fold mit-scheme


【解决方案1】:

MIT Scheme 在其基础库中不包含fold 函数,只有fold-left and fold-right。但是,确实存在由 SRFI-1 声明的 fold 函数,它受 MIT 方案支持并表现出您描述的行为。

fold 函数是一个左折叠函数——也就是说,它通过从左到右的迭代来累加列表——但它与 MIT Scheme 的 fold-left 函数的不同之处在于累加器过程的参数顺序是翻转的。也就是说,fold 应用带有累加器参数 last 的过程,而 fold-left 应用带有累加器参数 first 的过程。

为了说明这一点,这就是如何根据fold-left 来定义fold

(define (fold proc init lst)
  (fold-left (lambda (x acc) (proc acc x)) init lst))

根据我的经验,fold 参数顺序在 Lisp 实现中更常见,而fold-left 参数顺序在其他函数式语言中更常见。提供acc 参数last 的原因正是您发现的原因:它可以更轻松地将foldcons 类似的过程一起使用,这些过程接受累积值作为它们的第二个参数。


顺便说一句,您似乎在原始问题中混淆了fold-leftfold-right:返回列表不变的是fold-right,返回反向对集的是fold-left。如果您了解fold-leftfold-right 是如何定义的,那么这是有道理的。

以某种方式,fold-leftfold-right 都从 left 开始折叠列表,因为 Scheme 列表是单链接的,不能从右侧读取。区别在于左折叠是迭代的,而右折叠是递归的。

左折叠对每个元素一个一个地应用一个过程,然后将结果线程化到下一个应用程序中。当被视为嵌套应用程序时,这最终会颠倒元素的顺序:

(proc eN ... (proc e1 (proc e0 init)) ...)

相比之下,右折叠递归地应用该过程,在嵌套应用程序中保持顺序一致:

(proc e0 (proc e1 ... (proc eN init) ...))

当与cons 一起使用时,左折叠反转,但右折叠只是标识。

(这在 Haskell 等惰性语言中可能更有趣,因为右折叠并不依赖于整个列表,尽管据说是“从右边”开始的,所以它可以在无限流上运行......然而,这不太相关在方案中。)

【讨论】:

    猜你喜欢
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    • 1970-01-01
    • 2012-10-24
    • 2011-12-19
    • 1970-01-01
    相关资源
    最近更新 更多