【问题标题】:Flattening lazy list of lazy lists in Scheme via higher-order accumulation procedure通过高阶累加过程展平 Scheme 中惰性列表的惰性列表
【发布时间】:2014-05-01 10:14:44
【问题描述】:

我正在尝试找到一个实现,它使用我编写的程序 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 &gt; 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 过程。

关于如何使它工作的任何建议?

【问题讨论】:

  • 虽然您提供的代码显示您正在尝试的内容很好,但不幸的是,headtailall-div-from 没有定义,所以(对我来说)很难说出问题是。另外,你能举一个输入和正确输出的例子吗?
  • 感谢回复,我马上就做!
  • @GregHendershott,我添加了缺失的程序和一个正确的例子
  • 您是否验证过您的其他功能,例如lz-lst-maplz-lst-filter?

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


【解决方案1】:

您的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 . &lt;proc1&gt;) . &lt;proc2&gt; ),但对 (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 ....)))

产生一个惰性列表。

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

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

现在可以正常运行了:

(取 (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 以按顺序组合流,并在all-mults-from 定义中切换到mults-above-of,则(lz-lst-accumulate interleave-ordered '() (all-mults-from-above 2)) 将按顺序定义所有合数的惰性列表,通过就像在埃拉托色尼的筛子中一样计数。

从这里开始,这只是让自己拥有自己的lazy unbounded incremental sieve of Eratosthenes (在该页面上搜索“SiCp”)的又一步。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 2020-10-10
    • 2012-02-10
    • 2020-12-28
    相关资源
    最近更新 更多