你如何在方案中实现一个简单的列表迭代器?
Posted
技术标签:
【中文标题】你如何在方案中实现一个简单的列表迭代器?【英文标题】:How do you implement a simple list iterator in scheme? 【发布时间】:2021-12-01 12:04:49 【问题描述】:我正在尝试仅使用基本函数(car、cdr、cons 等)比较 Scheme 中列表列表中的条目,但不知道如何迭代列表。我试着写这个:
(define (iterate L X)
(cond ((null? L) '())
((> X 0) (iterate ((cdr L) (- X 1))))
))
但我不确定为什么它不起作用。我的想法是迭代只会返回 n cdr 之后的列表列表。例如,我试图得到:
(iterate ( ((10 20) (20 30) (30 40) (40 50)) '2)) -> ((30 40) (40 50))
(iterate ( ((10 20) (20 30) (30 40) (40 50)) '3)) -> ((40 50))
这是我得到的错误,不知道是什么意思:
*** ERROR: invalid application: (20 30)
Stack Trace:
_______________________________________
0 (20 30)
At line 45 of "./main.sc"
1 ((10 20) (20 30) (30 40) (40 50))
At line 45 of "./main.sc"
2 (((10 20) (20 30) (30 40) (40 50)) '3)
At line 45 of "./main.sc"
3 (iterate (((10 20) (20 30) (30 40) (40 50)) '3))
At line 45 of "./main.sc"
感谢任何帮助。谢谢!
【问题讨论】:
您正在尝试使用cdr
返回的列表,就像它是一个可以调用的函数一样。
【参考方案1】:
有两个基本问题:
-
在 Scheme 中不要用括号括起函数参数;语法是
(function arg1 arg2)
,而不是(function (arg1 arg2))
。后者首先将过程arg1
应用于arg2
,然后将其结果传递给function
。
((10 20) (20 30) (30 40) (40 50))
不会创建列表,它会尝试将过程(10 20)
应用于参数(20 30)
、(30 40)
和(40 50)
。您的实现首先评估第一个参数 - (20 30)
- 在 (10 20)
之前,这会尝试将 20
作为过程应用到参数 30
。这是“无效申请”。
(如果首先评估该过程,您会看到“无效的应用程序:(10 20)”。)
您需要引用您的列表参数或使用list
过程。
解决这两个问题
(define (iterate L X)
(cond ((null? L) '())
((> X 0) (iterate (cdr L) (- X 1)))))
和
(iterate '((10 20) (20 30) (30 40) (40 50)) '3)
现在你只需要修复X
在列表为空之前达到零的问题...
【讨论】:
【参考方案2】:基本上,Scheme 中的所有控制流,甚至是报告中的控制流,都是递归过程的语法糖。例如。当你用 JS 写这个的时候:
const arr = [];
for (let e of lst)
arr.push(e*2);
return arr;
在Scheme中你会这样写:
(define (loop lst acc)
(if (null? lst)
(reverse acc)
(loop (cdr lst) (cons (* (car lst) 2) acc))))
(loop lst '())
我们甚至还有一个语法糖可以更清楚地做到这一点:
(let loop ((lst lst) (acc '()))
(if (null? lst)
(reverse acc)
(loop (cdr lst) (cons (* (car lst) 2) acc))))
在 JS 中,我们有 Array.forEach
、Array.reduce
和 Array.map
。在 Scheme 中,我们有 for-each
、fold-left
、fold-right
和 map
。例如。上面的代码在JS中可以这样写:
[1, 2, 3, 4].map(v => v*2); // ==> [2, 3, 6, 8]
在Scheme中像这样:
(map (lambda (v) (* v 2)) lst) ; ==> (2 3 6 8)
所以我猜你不能使用这些列表过程,但你可以自己创建它,或者像我的第一个例子一样滚动你自己的递归。
【讨论】:
以上是关于你如何在方案中实现一个简单的列表迭代器?的主要内容,如果未能解决你的问题,请参考以下文章