通过高阶累积过程展平Scheme中惰性列表的惰性列表

时间:2014-05-01 10:14:44

标签: scheme racket lazy-evaluation lazy-sequences accumulate

我试图找到一个使用interleavelz-lst-accumulate延迟惰性列表惰性列表的实现,这些是我编写的过程。这是到目前为止的代码:

(define lz-lst-accumulate
  (lambda (op initial lz)
    (if (empty? lz)
      initial
      (op (head lz)
        (lambda() (lz-lst-accumulate op initial (tail lz)))))))

(define interleave
  (lambda (lz1 lz2)
    (if (empty? lz1)
      (lz2)
      (cons (head lz1)
        (interleave (lz2) (lambda() (tail lz1)))))))

(define all-div-from-flattened
     (lambda (lower)
       (lz-lst-accumulate interleave '() (all-div-from lower))))

(define take
  (lambda (lz-lst n)
    (if (= n 0)
      (list)
      (cons (car lz-lst)
        (take (tail lz-lst) (sub1 n))))))

(define head
  (lambda (lz)
    (car lz)))

(define tail
  (lambda (lz-lst)
    ((cdr lz-lst))))

(define lz-lst-map
  (lambda (f lz)
    (if (empty? lz)
      lz
      (cons (f (head lz))
        (lambda () (lz-lst-map f (tail lz)))))))

; Signature: all-div-from (low)
; Type: [Number -> Lazy-list]
; Purpose: return a lazy-list of lazy-lists. The nested lazy-lists 
;          correspond to the integers greater than lower in an 
;          increasing order. Each nested lazy-list is the list of 
;          all integers divisible by i for some i>=lower.
; Pre-conditions: low is an integer
; Tests: > (define lz3 (all-div-from 7))
;        > (take lz3 3)
;        '((7 . #<procedure>) (8 . #<procedure>) (9 . #<procedure>))
;        > (take (head lz3) 3)
;        '(7 14 21)
;        > (take (head (tail lz3)) 3)
;        '(8 16 24)

(define all-div-from
    (lambda(lower)
      (cons (lz-lst-map (lambda(x) (* x lower)) (div-from 1 1))
            (lambda() (all-div-from (add1 lower))))))


; Signature: div-from (low int)
; Type: [[Number*Number]-> Lazy-list]
; Purpose: return the lazy-list of all integers that 
;          are larger than low and divisible by int
; Pre-conditions: int > low
; Tests: > (define lz1 (div-from 5 12))
;        > (take lz1 3)
;        '(12 24 36)
;        > (define lz2 (div-from 7 10))
;        > (take lz2 4)
;        '(10 20 30 40)
(define div-from
  (lambda (lower int)
    (lz-lst-filter (lambda(x) (> x (- lower 1))) 
      (lz-lst-map (lambda(x) (* x int)) (integers-from 1)))))

(define integers-from
  (lambda (n) (cons n
    (lambda () (integers-from (+ 1 n))))))

(define lz-lst-filter
  (lambda (p lz)
    (cond ((empty? lz) lz)
          ((p (head lz)) 
             (cons (head lz) 
               (lambda () (lz-lst-filter p (tail lz)))))
          (else (lz-lst-filter p (tail lz))))))

过程all-div-from接收下限low并返回懒惰列表的惰性列表。其中的每个惰性列表都由div-from生成,它接收下限low和整数int > low,以及 返回大于low且可被int整除的所有整数的延迟列表。

输入和正确输出的示例:

 > (take (all-div-from-flattened 7) 10)
        '(7 8 14 9 21 16 28 10 35 24)

但是当我在翻译中尝试这一行时:

> (take (all-div-from-flattened 3) 3)

它进入无限循环。

我的实施必须使用lz-lst-accumulateinterleaveall-div-from-flattend程序。

有关如何使其发挥作用的任何建议吗?

1 个答案:

答案 0 :(得分:5)

您的interleave不会产生懒惰列表;它产生一个普通的列表:它使用带有两个参数的cons,第二个参数 not 包含在lambda中。因此cons迫使第二个参数通过,导致失控评估:

(define interleave
  (lambda (lz1 dlz2)    ; "delayed" lz2
    (if (empty? lz1)
      (dlz2)
      (cons (head lz1)
            ; here:
            (interleave (dlz2) (lambda () (tail lz1)))))))

(define lz-lst-accumulate
  (lambda (op initial lz)
    (if (empty? lz)
      initial
      (op (head lz)
          (lambda () (lz-lst-accumulate op initial (tail lz)))))))

(all-div-from lower)生成正确的输出( (lower . <proc1>) . <proc2> ),但对(lz-lst-accumulate interleave '() (all-div-from lower))的调用减少为

(interleave [lower . <proc1>]
            (lambda () (lz-lst-accumulate interleave '() (<proc2>))))

并且减少为

(cons lower 
      (interleave (lz-lst-accumulate interleave '() (<proc2>))
                  (lambda () (<proc1>))))

虽然它必须减少为

(cons lower 
      (lambda () (interleave ....)))

生成 lazy 列表。

显而易见的(现在)解决方案是添加缺少的lambda

(define interleave
  (lambda (lz1 lz2)
    (if (empty? lz1)
      (lz2)
      (cons (head lz1)
            (lambda () (interleave (lz2) (lambda() (tail lz1))))))))

现在它正确运行:

  

(take(all-div-from-flattened 7)10)
  ;价值12:(7 8 14 9 21 16 28 10 35 24)


您可以通过引入

来简化您的代码
(define integers-from-by
  (lambda (n d) (cons n
    (lambda () (integers-from (+ n d) d)))))

然后,

;(define div-from
;  (lambda (lower int)
;    (lz-lst-filter (lambda(x) (> x (- lower 1))) 
;      (lz-lst-map (lambda(x) (* x int)) (integers-from 1)))))

(define mults-from-of    ; n in [int, 2*int ..], n >= lower
  (lambda (lower int)
    (let ((x (* (quotient (+ lower (- int 1)) int) int)))
      (integers-from-by x int))))

你也可以

(define mults-above-of   ; n in [int, 2*int ..], n > lower
  (lambda (lower int)
    (let ((x (* (+ (quotient lower int) 1) int)))
      (integers-from-by x int))))

接下来,

; (define all-div-from
;    (lambda(lower)
;      (cons (lz-lst-map (lambda(x) (* x lower)) (div-from 1 1))
;            (lambda() (all-div-from (add1 lower))))))

(define all-mults-from
  (lambda (lower)
    (lz-lst-map (lambda (n) (mults-from-of n n))
                            ; or just (integers-from-by n n)
                (integers-from-by lower 1))))

如果您更改interleave按顺序组合流,并切换到mults-above-of定义中的all-mults-from,那么(lz-lst-accumulate interleave-ordered '() (all-mults-from-above 2))将定义所有复合的惰性列表数字,按顺序,通过在Eratosthenes的筛子中计数。

从这一点开始,让自己成为自己的lazy unbounded incremental sieve of Eratosthenes (在该页面上搜索&#34; SiCp&#34;)只需再迈出一步。

另一个评论:take应该调整为不强制流的额外元素。更多here