我正在尝试使用流来生成Scheme中的素数列表,并且遇到了一个我无法理解的错误。我花了好几个小时尝试不同的事情,觉得我有点理解这个问题,但我无法完全理解它。我看过类似的帖子,但我认为我没有足够的经验可以将它们与我的问题联系起来。
(define int-builder$
(lambda (n)
(cons n (lambda() (int-builder$ (+ n 1))))))
(define filter-out-mults$
(lambda (num lst)
(if (= (modulo (car lst) num) 0)
(filter-out-mults$ num (cdr lst))
(cons (car lst) (lambda () (filter-out-mults$ num (cdr lst)))))))
(define take$
(lambda (m s)
(if (or (= m 0) (null? s))
'()
(cons (car s) (take$ (- m 1) ((cdr s)))))))
int-builder $从n开始生成无限的整数流。 filter-out-mults $应过滤掉任何非素数。取$从列表中取出前m个素数。
以下是我运行它的方式以及错误消息:
> (take$ 10 (filter-out-mults$ 2 (int-builder$ 2)))
mcar: contract violation
expected: mpair?
given: #<procedure:.../prime-stream.ss:10:8>
我认为问题与如何在if / else语句中调用filter-out-mults $有关,因为没有传入新的int / procedure对,但我似乎无法弄清楚如何要解决这个问题。任何帮助将不胜感激。
答案 0 :(得分:2)
我在发布后不久就设法回答了我自己的问题,并希望分享我的解决方案。
在filter-out-mults $中,每个
(cdr lst)
需要
((cdr lst))
由于int-builder $是一个流,它返回包含整数的对和一个获取下一个整数标记的过程。例如:
> (int-builder$ 2)
(2 . #<procedure:...prime-stream.rkt:10:8>)
为了获得下一个整数,需要调用该过程。问题是(cdr lst)将返回该过程,但不会调用它。举例说明:
> (cdr (int-builder$ 2))
#<procedure:...prime-stream.rkt:10:8>
添加额外的括号后,返回下一对:
> ((cdr (int-builder$ 2)))
(3 . #<procedure:...hedgerh.lab6.rkt:10:8>)
希望这有助于某人。
以下是filter-out-mults $的完整定义:
(define filter-out-mults$
(lambda (num lst)
(if (null? lst)
'()
(if (= (modulo (car lst) num) 0)
(filter-out-mults$ num ((cdr lst)))
(cons (car lst) (lambda () (filter-out-mults$ num ((cdr lst)))))))))
答案 1 :(得分:2)
这可以通过SRFI-41 Streams library来解决。它在许多实现中都可用,包括Racket。 Racket还有it's own stream library许多类似的过程/语法。 SRFI-41可从#!Racket和#!R6RS获得。
;(import (rnrs) (srfi :41)) ; For #!R6RS language
(require srfi/41) ; For #!Racket language
(define-stream (filter-out-multipliers n v stream)
(let ((a (stream-car stream)))
(cond ((< a n) (stream-cons a (filter-out-multipliers n v (stream-cdr stream))))
(else (filter-out-multipliers (+ n v) v (if (= a n) (stream-cdr stream) stream))))))
(define-stream (primes stream)
(let ((a (stream-car stream)))
(stream-cons a (primes (filter-out-multipliers (+ a a) a (stream-cdr stream))))))
(stream->list (stream-take 20 (primes (stream-from 2))))
; ==> (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71)