Scheme 实现可能使用什么顺序,为什么?让我们尝试一下(所有代码都在 Chez Scheme REPL 中运行):
- 应用程序的显示顺序
> (filter (lambda (x) (display x) (even? x))
'(0 1 2 3 4 5)))
452301(0 2 4)
>
- 为什么是这个命令?
R6RS 实现必须检查这list
是一个正确的列表
> (filter (lambda (x) (display x) (even? x))
'(0 1 2 . 3)))
Exception in filter: (0 1 2 . 3) is not a proper list
>
> (define xs '(0 1 2 3))
> (set-cdr! (cdddr xs) (cdr xs))
> (filter (lambda (x) (display x) (even? x)) xs)
Exception in filter: (0 1 2 3 1 2 ...) is not a proper list
>
- Chez Scheme 中的实现,
filter
它在过滤时检查这些要求,导致谓词应用程序的“452301”顺序,可以在这里
看到
(第 589-617 行:下面包含一个版本作为扰流板,作为滚动浏览源代码的替代方案在github上)
- 什么?
Chez Scheme 代码使用“龟兔赛跑”算法
来检测周期。如果没有错误检查,代码可能是:
> (let ([filter
(lambda (pred? ls)
(let f ([fast ls])
(if (pair? fast)
(let ([rest (f (cdr fast))])
(if (pred? (car fast))
(cons (car fast) rest)
rest))
'())))])
(filter (lambda (x) (display x) (even? x))
'(0 1 2 3 4 5)))
543210(0 2 4)
>
(标识符fast
用于匹配 Chez Scheme 代码:可能是ls
其他情况)
- 如何将其更改为
pred?
“从头到尾”?
rest
用累加器替换变量(将以下与上面的 3 进行比较;变化很小,但过滤后的元素被cons
编辑为 acc,因此必须反转它才能给出结果):
> (let ([filter
(lambda (pred? ls)
(let f ([fast ls] [acc '()])
(if (pair? fast)
(f (cdr fast)
(if (pred? (car fast))
(cons (car fast) acc)
acc))
(reverse acc))))])
(filter (lambda (x) (display x) (even? x))
'(0 1 2 3 4 5)))
012345(0 2 4)
>
所以 4 可以用作 required filterfunc
。添加像 Chez Scheme 实现这样的错误检查将是一个有趣的练习,它实际上是:
(define (filter pred? ls)
(unless (procedure? pred?)
(error #f "not a procedure" pred?))
(or (let f ((pred? pred?) (fast ls) (slow ls))
(if (pair? fast)
(let ((fast1 (cdr fast)))
(if (pair? fast1)
(and (not (eq? fast1 slow))
(let ((fast2 (cdr fast1)))
(let ((rest (f pred? fast2 (cdr slow))))
(and rest
(if (pred? (car fast))
(if (pred? (car fast1))
(if (eq? rest fast2)
fast
(list* (car fast)
(car fast1) rest))
(cons (car fast) rest))
(if (pred? (car fast1))
(if (eq? rest fast2)
fast1
(cons (car fast1) rest))
rest))))))
(and (null? fast1)
(if (pred? (car fast))
fast
'()))))
(and (null? fast) '())))
(error #f "circular/improper list" ls)))