List 我如何用渴望的语言列出懒惰的清单?
我想在计划中列一个懒惰的清单。这就是我目前所拥有的List 我如何用渴望的语言列出懒惰的清单?,list,functional-programming,scheme,lazy-evaluation,operator-precedence,List,Functional Programming,Scheme,Lazy Evaluation,Operator Precedence,我想在计划中列一个懒惰的清单。这就是我目前所拥有的 ;; 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 (l
;; 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在不进行任何计算的情况下接受这个内部表达式?解决方案是使用宏。我不是方案专家(尤其不是宏方面的专家),但也许这段代码可以作为灵感:
(define-syntax pointer-to
(syntax-rules ()
((pointer-to var)
(make-pointer
(lambda () var) ; the "pointer dereference" operation
(lambda (value) (set! var value)))))) ; "pointer write"
它的用法如下:
(define x 1)
(define px (pointer-to x))
(pointer-set! px 2) ; this (in some sense) becomes `(set! x 2)'
(define (lazy-list from)
(cons from (λ() (lazy-list (+ from 1)))))
所以也许你想要像这样的东西
(define-syntax lazy-cons
(syntax-rules ()
((lazy-cons head lazytail)
(cons head (lambda () lazytail)))))
但我不确定。查看
定义语法方案中的惰性列表称为流 如果您不想走宏路线,您可以随时放弃cons-stream
并重写lazy-list
,如下所示:
(define x 1)
(define px (pointer-to x))
(pointer-set! px 2) ; this (in some sense) becomes `(set! x 2)'
(define (lazy-list from)
(cons from (λ() (lazy-list (+ from 1)))))
这可能是最简单、最实用的解决方案,但它只适用于创建递增数字的惰性列表。您可以通过传入一个函数来概括这一点,该函数将在调用时生成列表的连续元素:
(define (lazy-list-gen generator)
(cons (generator)
(λ() (lazy-list-gen generator))))
(define (lazy-list from)
(lazy-list-gen
(λ()
(let ((ret from))
(set! from (+ from 1))
ret))))
这很有效:
> (define x (lazy-list 1))
> (car-stream x)
1
> (car-stream (cdr-stream x))
2
但代码中有一个bug:
... continuing from above ...
> (car-stream (cdr-stream x))
3
发生此错误的原因是对cdr流的调用
再次调用generator
。我们可以通过缓存lambda的返回值来解决这个问题:
(define (lazy-list-gen generator)
(cons (generator)
(let ((gen-cache #f))
(λ()
(cond ((not gen-cache)
(set! gen-cache (lazy-list-gen generator))))
gen-cache))))
现在,它可以正常工作了:
> (define x (lazy-list 1))
> (car-stream x)
1
> (car-stream (cdr-stream x))
2
> (car-stream (cdr-stream x))
2
> (car-stream (cdr-stream (cdr-stream x)))
3
> (car-stream (cdr-stream x))
2
你真的应该看看
特别是,由递归函数创建的惰性流将在急切语言中严重泄漏内存,除非您特别避免它。要做到这一点,您还需要使递归函数变得懒惰,而不是急切。这意味着您的惰性实现需要是,它导出延迟、强制和惰性。递归构建流的函数必须将它们的主体封装在lazy中。Darn,现在我也想学习Scheme:-DIts not Scheme,但是这个页面在F#中有一个lazy列表的实现:我没有看到家庭作业标记。这是一个学术练习、学习练习,还是用于更大的项目?SRFI-40或SRFI-41有什么问题?哇。成功了。但是你能评论一下你的代码吗。我不知道如何以及何时使用宏。我会尽我最大的努力。“(define syntax NAME(syntax rules()((NAME ARG1 ARG2…)SOME_EXPRESSION)))”意味着:每当解析器看到(NAME ARG1 ARG2…)它就会用某个_EXPRESSION替换它,在某个_EXPRESSION中进行参数替换。对于惰性cons,它将(惰性cons 1(列表12))重写为(cons 1(lambda()(列表12)))。注意,head接受了“value”1(实际上是语法树1)并插入到cons中;懒尾巴有“价值”(清单12)而且。。。“插入”呼叫cons。它与C和C++中的宏有点相似,但更好的是:是的。如果你看一下我的程序,我正在尝试生成一个流。你应该知道SICP流不是完全懒惰的(流的头是严格的),这在某些情况下可能会导致问题。另一个答案中提到的SRFI-41在所有情况下都提供完全惰性流。