定义reverse 就像使用cons 将现有列表折叠到一个新的空列表一样简单
(define (reverse xs)
(foldl cons '() xs))
要了解它的工作原理,请评估折叠
(reverse '(1 2 3)) ;; ⇒ ?
;; first iteration
(cons 1 '()) ;; ⇒ '(1)
;; second iteration
(cons 2 '(1)) ;; ⇒ '(2 1)
;; third iteration
(cons 3 '(2 1)) ;; ⇒ '(3 2 1)
在您的评论中,您询问了如何实现foldl
(define (foldl f y xs)
(if (empty? xs)
y
(foldl f
(f (car xs) y)
(cdr xs))))
如果你不熟悉折叠,我认为用sum 函数演示它们是最简单的。
如果你想总结一个数字列表1 2 3 4,你会怎么做?大概是这样的
1 + 2 + 3 + 4
你看到+ 放在它们之间了吗?让我们看看我们会如何评估这个
((1 + 2) + 3) + 4
(3 + 3) + 4
6 + 4
⇒ 10
foldl 正是这样做的。它需要一个二进制过程、一个初始值和一个列表。在我们的例子中,我们将使用过程+ 和0 的初始值进行演示。这次我们将展示使用 s 表达式((+ x y) 而不是中缀 x + y)的评估
(foldl + 0 '(1 2 3 4))
(+ 4 (+ 3 (+ 2 (+ 1 0))))
(+ 4 (+ 3 (+ 2 1)))
(+ 4 (+ 3 3))
(+ 4 6)
⇒ 10
这个初始值很重要,因为如果输入是一个空列表,我们需要知道期望返回什么样的值
(foldl + 0 '())
;; ⇒ 0
所以,让我们用折叠来定义sum
(define (sum xs) (foldl + 0 xs))
(sum '(1 2 3 4)) ;; ⇒ 10
(sum '()) ;; ⇒ 0
总和对我们来说很容易理解,因为它们对我们来说非常熟悉,但 reverse 过程可能不那么清楚。折叠减少为单个值,在我们的例子中,我们将输入列表减少为单个输出列表。
让我们快速回顾一下sum 的评估。记住我们折叠的过程是+,初始值为0
(foldl + 0 '(1 2 3 4))
(+ 4 (+ 3 (+ 2 (+ 1 0))))
(+ 4 (+ 3 (+ 2 1)))
(+ 4 (+ 3 3))
(+ 4 6)
⇒ 10
现在让我们看看写出的reverse 评估。这里我们折叠的过程是cons,初始值为'()(空列表)
(foldl cons '() '(1 2 3))
(cons 3 (cons 2 (cons 1 '())))
(cons 3 (cons 2 '(1)))
(cons 3 '(2 1))
⇒ '(3 2 1)