预期违反合同:数量?给定:#<procedure:runtime>参数位置:其他第二个参数...:1535481725945

时间:2018-08-28 20:42:50

标签: scheme sicp

尝试在此代码中检查输入号是否为偶数:

(define (square n)
  (* n n))
(define (smallest-divisor n)
  (find-divisor n 2))

(define (find-divisor n test-divisor)
  (cond
    ((> (square test-divisor) n) n)
    ((divides? test-divisor n) test-divisor)
    (else (find-divisor n (+ test-divisor 1)))))

(define (divides? a b)
  (= (remainder b a) 0))

(define (prime? n)
  (= n (smallest-divisor n)))

(define (runtime)
  (current-milliseconds))

(define (timed-prime-test n)
  (newline)
  (display n)
  (start-prime-test n runtime 1))

(define (start-prime-test n start-time count)
  (if (prime? n)
    (report-prime (- (runtime) start-time)
                  (+ count 1)
                  (display "tut"))
    (+ n 1))
  (if (even? n)
    (+ n 1)
    (display "n is uneven"))
  (if (= count 3)
    (display "done")
    (start-prime-test (+ n 1) runtime count)))

(define (report-prime elapsed-time)
  (display " *** ")
  (display elapsed-time))

(timed-prime-test 4)

看到此错误:

contract violation 
  expected: number?
  given: #<procedure:runtime>
  argument position: 2nd 
  other arguments...: 1535481725945

有人可以告诉我怎么了吗?

1 个答案:

答案 0 :(得分:1)

第一个问题是runtime函数的两次使用。该错误消息表明它得到了 function runtime,该位置应有数字。可能是调用函数的结果。这意味着您在某处引用该函数而不调用它。

此:

> runtime
#<procedure:runtime>

代替此:

> (runtime)
1535490725945

请记住,要调用一个函数,即使它是一个零参数的函数,也必须将其包装在括号中。

您在3个地方使用了runtime函数,在其中2个地方(在timed-prime-test内和start-prime-test的第3个if语句中),您使用的是裸函数,而没有调用它。

将这两个位置从runtime更改为(runtime)可以消除contract violation expected: number? given: #<procedure:runtime>错误。

这解决了您的第一个问题。

但是背后还有另一个错误:

report-prime: arity mismatch;
 the expected number of arguments does not match the given number
  expected: 1
  given: 3
  arguments...:
   0
   2
   #<void>

这来自您在report-prime函数的第一个if语句中对start-prime-test的调用。

我不知道您打算将此代码或report-prime函数用于什么。可能是定义错误,应该使用更多参数,也可能是调用错误,并且只能传入一个参数。

您打算选哪个人?

更新:使用1个参数调用report-prime,然后执行2个操作

  

我只想向其中传递1个参数((- (runtime) start-time)),并且在它执行功能后,我要始终执行两个操作((+ count 1)(display "tut")

要执行一系列操作,应使用begin,如下所示:

(begin
  action1
  action2
  ...)

现在,(+ count 1)不是一个“动作”,但这是一个单独的问题。如果您打算将其用作操作,则它将进入此begin块内。

这意味着在start-prime-test的第一个if语句中,替换为:

(report-prime (- (runtime) start-time)
              (+ count 1)
              (display "tut"))

与此:

(begin
  (report-prime (- (runtime) start-time))
  (+ count 1)
  (display "tut"))

有了这一更改,report-prime: arity mismatch错误就消失了。

这解决了您的第二个问题。

这背后还有另一个问题,无限循环。您的代码将显示:

4 *** 0tutn is uneven *** 0tutn is unevenn is uneven *** 0tutn is uneven *** 0tutn is unevenn is uneven *** 0tutn is uneven *** 0tutn is unevenn is uneven *** 0tutn is 
unevenn is unevenn is uneven *** 0tutn is uneven *** 0tutn is unevenn is unevenn is uneven *** 0tutn is unevenn is uneven *** 0tutn is uneven *** 0tutn is unevenn is uneven
*** 0tutn is unevenn is unevenn is uneven *** 0tutn is unevenn is unevenn is uneven *** 0tutn is uneven *** 0tutn is unevenn is unevenn is uneven *** 0tutn is unevenn is 
uneven *** 0tutn is uneven *** 0tutn is unevenn is unevenn is uneven *** 0tutn is unevenn is uneven *** 0tutn is unevenn is unevenn is uneven *** 0tutn is unevenn is uneven

它一直这样,永不停止。

我建议您提出一个单独的问题来解决此问题,因为无限循环是与合同违约相比要解决的另一种问题。

但是,首先,您可能想阅读有关如何在函数式编程中使用递归的教程。要点是,需要有一个基本案例,该案例总是停止的,而任何递归案例都需要与该基本案例“更接近”,以了解更接近的定义。