我定义了一个从零开始的所有整数的简单惰性列表:
(define integers-from
(lambda (n)
(cons n
(lambda () (integers-from (+ 1 n))))))
(define lz (integers-from 0))
我还编写了一个将懒惰列表作为参数
的控制器(define lz-lst-accumulate
(lambda (op initial lz)
(if (null? lz)
initial
(cons (op (head lz) initial)
(lambda () (lz-lst-accumulate op (op initial (head lz)) (tail lz)))))))
这个控告者是否回答了懒惰列表的格式? 这是对累加器的简单测试:
(define acc (lz-lst-accumulate * 1 lz))
(take acc 4)
=> '(1 2 6 24)
take
是一个辅助函数,它从惰性列表的第一个n
元素创建一个列表:
(define head car)
(define tail
(lambda (lz-lst)
((cdr lz-lst)) ))
(define take
(lambda (lz-lst n)
(if (= n 0)
(list)
(cons (car lz-lst)
(take (tail lz-lst) (sub1 n)))) ))
答案 0 :(得分:5)
在lz-lst-accumulate
中,您计算一次(op (head lz) initial)
,然后再计算(op initial (head lz))
。这是不一致的;两者应该是相同的,实际只计算一次,因为它是相同的值:
(define lz-lst-accumulate
(lambda (op initial lz)
(if (lz-lst-empty? lz)
initial
(let ((val (op (head lz) initial)))
(cons val
(lambda () (lz-lst-accumulate op val (tail lz))))))))
仅在您的示例中使用数字,因为您使用了类型对称操作*
。使用cons
它将无效。
除此之外没关系。实际上,lz-lst-accumulate
在Haskell中通常被称为left fold(scanl
,因为您生成了“累积”值foldl f z xs = last (scanl f z xs)
)的进展。
re:您的take
版本,它正在强制流的一个太多元素。更好地做到这一点
(define take
(lambda (lz n)
(if (or (<= n 0) (lz-lst-empty? lz))
(list)
(if (= n 1)
(list (car lz)) ; already forced
(cons (car lz)
(take (tail lz) (sub1 n)))))))
因此它只会强制生成尽可能多的元素,而不是一个元素(可能是例如(/ 1 0)
的分歧,无缘无故地使整个计算无效)。
这样,SRFI 41 ((take 4 (stream-map 1/ (ints-from-by 4 -1)))
) 中的反例就会正常工作 (它会在不强制(1/4 1/3 1/2 1/1)
的情况下计算1/0
,take
的正常版本(就像您正在使用的版本一样)会这样做。