如何在Guile计划中使用懒惰评估?

时间:2016-08-04 22:15:42

标签: scheme lazy-evaluation guile

我编写了一个代码,它使用延迟评估来生成无限的数据结构,但是有一个错误。

以下是代码:

#!/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计划中使用懒惰评估?

2 个答案:

答案 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-streamstream-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