如何用 Eager 语言制作惰性列表?
我想在Scheme中制作一个惰性列表。 这是我到目前为止所拥有的。
;; Constructor for Pairs
(define (cons-stream a b)
(cons a (λ() b)))
;; Selectors
(define (car-stream a-stream)
(car a-stream))
(define (cdr-stream a-stream)
((cdr a-stream)))
;; Lazy List using the pairs
(define (lazy-list from)
(cons-stream from (lazy-list (+ from 1))))
;; Take function
(define (take a-lazy-list number)
(define (take-helper i )
(if(= i number)
empty
(cons (car a-lazy-list) (take-helper (+ i 1)))))
(take-helper 0))
惰性列表的问题在于,Scheme 首先计算内部表达式(惰性列表(+ from 1)),导致过程进入无限递归。
有没有办法让 con-stream 接受这个内部表达式而不进行任何评估?
I wanted to make a lazy list in Scheme. This is what I have so far.
;; Constructor for Pairs
(define (cons-stream a b)
(cons a (λ() b)))
;; Selectors
(define (car-stream a-stream)
(car a-stream))
(define (cdr-stream a-stream)
((cdr a-stream)))
;; Lazy List using the pairs
(define (lazy-list from)
(cons-stream from (lazy-list (+ from 1))))
;; Take function
(define (take a-lazy-list number)
(define (take-helper i )
(if(= i number)
empty
(cons (car a-lazy-list) (take-helper (+ i 1)))))
(take-helper 0))
The problem with the lazy-list is that Scheme evaluates the inner expression (lazy-list (+ from 1)) first causing the procedure to go into an infinite recursion.
Is there a way to make the con-stream take this inner expression without any evaluation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
解决方案是使用宏。 我不是方案专家(尤其不是宏专家),但也许这个片段可以作为灵感:
它的用法如下:
所以也许你想要类似的东西
但我不确定。 看看
define-syntax
。The solution is to use a macro. I'm no scheme expert (especially not on macros), but maybe this snippet can serve as inspiration:
It's used as follows:
So maybe you want something like
But I'm not sure. Have a look at
define-syntax
.如果你不想走宏观路线,你总是可以放弃
cons-stream
并重写lazy-list
如下:这可能是最简单、最实用的解决方案,但它只适用于制作递增数字的惰性列表。 您可以通过传入一个函数来概括这一点,该函数在调用时将生成列表的连续元素:
这工作得很好:
但是代码中有一个错误:
发生此错误是因为调用
cdr-stream
再次调用生成器
。 我们可以通过缓存 lambda 的返回值来解决这个问题:现在它可以正常工作了:
If you don't want to go the macro route, you could always just abandon
cons-stream
and rewritelazy-list
as follows:This is probably the easiest, most pragmatic solution, but it's only good for making lazy lists of incrementing numbers. You could generalize this by passing in a function that will generate successive elements of the list when called:
This works pretty well:
But there's a bug in the code:
This error happens because the call to
cdr-stream
callsgenerator
again. We can solve this by caching the return value of the lambda:Now it works as it should:
Scheme 中的惰性列表称为流。 这是标准介绍。
A lazy list in Scheme is known as a stream. Here's the standard introduction.
你真的应该看看 SRFI-41
特别是,由在急切的语言中,递归函数会严重泄漏内存,除非您特别避免它。 为此,您还需要使递归函数变得懒惰,而不是急切。 这意味着您的惰性实现需要是SRFI-45,它导出延迟、强迫、和懒惰。 递归构建流的函数必须将其主体包装在惰性中。
You should really look at SRFI-41
In particular, lazy streams created by recursive functions will leak memory badly in an eager language, unless you specifically avoid it. To do so, you need to make recursive functions lazy also, not eager. This means that your laziness implementation needs to be SRFI-45, which exports delay, force, and lazy. Functions that build streams recursively must wrap their bodies in lazy.