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在所有情况下都提供完全惰性流。