我编写了一个代码,它使用延迟评估来生成无限的数据结构,但是有一个错误。
以下是代码:
#!/usr/bin/guile \
-e main -s
!#
(define ints-f
(lambda (n)
(let ((n1 (delay (ints-f (+ n 1)))))
(cons n (force n1)))))
(define (main args)
(display (car (ints-f 3) ))
(newline)
)
这会产生一个错误,表示堆栈溢出。这意味着即使没有被调用也会执行强制。如何纠正这个?
#!/usr/bin/guile \
-e main -s
!#
(define ints-f
(lambda (n)
(let ((n1 (delay (ints-f (+ n 1)))))
(cons n n1))))
(define (main args)
(display (car (ints-f 3) ))
(newline)
)
上面的代码给出了3的预期输出,但如果我在下面的代码中使用cdr
#!/usr/bin/guile \
-e main -s
!#
(define ints-f
(lambda (n)
(let ((n1 (delay (ints-f (+ n 1)))))
(cons n n1))))
(define (main args)
(display (cdr (ints-f 3) ))
(newline)
)
它打印一个promise对象。
如何在guile计划中使用懒惰评估?
答案 0 :(得分:1)
第一个代码段不正确,您在构建序列时强制执行该值,从而无法实现延迟评估的全部目的。另一方面,第二个片段看起来是正确的 - 虽然它可以简化一点:
(define (ints-f n)
(cons n (delay (ints-f (+ n 1)))))
正常在致电cdr
时获得承诺,它是使用delay
构建的thunk,仅在{force
时产生价值1}} d。事实上,如果你想要查看无限序列的元素,你必须使用一个程序来遍历你感兴趣的部分:
(define (take seq n)
(if (= n 0)
'()
(cons (car seq)
(take (force (cdr seq)) (- n 1)))))
类似地:
(define (get seq idx)
(if (= idx 0)
(car seq)
(get (force (cdr seq)) (- idx 1))))
例如:
(take (ints-f 5) 5)
=> '(5 6 7 8 9)
(get (ints-f 5) 5)
=> 10
答案 1 :(得分:1)
您是否尝试创建流?您可能希望参考(srfi srfi-41)
模块来实现该功能。 (披露:我编写了模块代码的Guile特定部分;其他所有部分都是从the reference implementation移植的。)
(use-modules (srfi srfi-41))
(define-stream (ints-f n)
(stream-cons n (ints-f (1+ n))))
请注意,define-stream
和stream-cons
是一起工作以在幕后构建(SRFI 45 - 样式)delay
/ force
的宏。 >†
用法示例:
> (stream->list 10 (ints-f 100))
(100 101 102 103 104 105 106 107 108 109)
†特别是,您的功能扩展为:
(define (ints-f n)
(lazy (eager (cons (delay n)
(lazy (ints-f (1+ n)))))))
你可以使用:
> (define x (ints-f 100))
> (force (car (force x)))
100
> (force (car (force (cdr (force x)))))
101