方案:“mcar:合同违规,预期:mpair,给出:#

时间:2014-04-07 12:02:57

标签: lambda stream functional-programming scheme racket

我正在尝试使用流来生成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对,但我似乎无法弄清楚如何要解决这个问题。任何帮助将不胜感激。

2 个答案:

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