为什么我得到#<undef>不是函数错误?

时间:2017-05-28 05:33:26

标签: scheme

这是我的代码,我有点困惑,为什么我收到此错误。我的代码只是找到二次方程的根。

(define (roots a b c)
  (define det
    (- (* b b) (* 4 a c))
  )
  (if (> det 0) (
                  (display (/ (+ (* b -1) (sqrt det)) (* 2 a)))
                  (display (/ (- (* b -1) (sqrt det)) (* 2 a)))
                )
  )
  (if (= det 0) (
                   (display (/ (* b -1) (* 2 a)))
                  (display (/ (* b -1) (* 2 a)))
                )
  )
  (if (< det 0) (
                  (display "complex roots")
                  (display (/ (+ (* b -1) sqrt(* det -1)) (* 2 a)))
                  (display (/ (- (* b -1) sqrt(* det -1)) (* 2 a)))
                )               
  )
)

(roots -2 4 5)
(roots -2 4 -5)

2 个答案:

答案 0 :(得分:2)

我相信你的意思是在你的单人身上添加一个begindisplay过程具有void返回值,额外的括号将尝试将该值应用为过程。您可以通过运行((display 5))来重现错误。使用begin将允许您改为按顺序评估表达式。

此代码将显示值,没有任何例外:

(define (roots a b c)
  (define det
    (- (* b b) (* 4 a c))
  )
  (if (> det 0) (begin
                  (display (/ (+ (* b -1) (sqrt det)) (* 2 a)))
                  (display (/ (- (* b -1) (sqrt det)) (* 2 a)))
                )
  )
  (if (= det 0) (begin
                   (display (/ (* b -1) (* 2 a)))
                  (display (/ (* b -1) (* 2 a)))
                )
  )
  (if (< det 0) (begin
                  (display "complex roots")
                  (display (/ (+ (* b -1) sqrt(* det -1)) (* 2 a)))
                  (display (/ (- (* b -1) sqrt(* det -1)) (* 2 a)))
                )               
  )
)

答案 1 :(得分:2)

Scheme中的括号非常特殊。他们的意思是apply

(define (test arg) arg)

((test +) 4 5) ; ==> 9

在JavaScript中也一样:

const plus = (a, b) => a+b; // Needed since + is not a function in JS
const test = arg => arg

test(plus)(4,5) // ==> 9

在您的代码中,您有:

((display (/ (+ (* b -1) (sqrt det)) (* 2 a)))
 (display (/ (- (* b -1) (sqrt det)) (* 2 a))))

不幸的是,运算符位置中的表达式返回#<undef>。实际上,根据规范,它可以返回任何,因为它在规范中未定义。虽然它不是一个功能所以它是你的特定实现,所以它就像:

((test 'symbol) 4 5); ==> Error: symbol is not a function

如前所述,调用test之前的工作确实有效,因此操作员位置的表达式是完全有效的代码,几乎不可能在编译时进行推理,但在运行时它会变得很明显。当申请获得非功能时,无法继续。

现在有些宏使用括号来表示应用程序以外的其他内容,您只需知道或阅读文档即可。一个例子是cond

(cond ((= 3 5) #t)
      (else #f))
; ==> #f

如果您之前从未见过cond,那么很容易假设((= 3 5) #t)是一种表达方式,当然,通过查看它,它应该不起作用(= 3 5) 1}}不会评估函数对象而是布尔值。但是,cond中的每个字词都会评估它car,然后在该字词的其余部分中的每个元素按顺序排列,如果它恰好是真值。

按顺序执行更多表达式并返回使用begin的最后一个表达式的值:

(begin 1 2 3)
; ==> 3

此处评估12显然是死代码,因为它没有做任何事情。因此,继承使用begin意味着副作用,其中返回值不重要,但副作用是。我不认为你的功能确实需要副作用:

(define (roots a b c)
  (define det
    (- (* b b) (* 4 a c)))
  (cond ((> det 0)
         (list (/ (+ (* b -1) (sqrt det)) (* 2 a))
               (/ (- (* b -1) (sqrt det)) (* 2 a))))
        ((= det 0)
         (list (/ (* b -1) (* 2 a))))
        ((< det 0)
         (list (/ (+ (* b -1) (make-rectangular 0 (sqrt (* det -1)))) (* 2 a))
               (/ (- (* b -1) (make-rectangular 0 (sqrt (* det -1)))) (* 2 a))))))

(roots -1 4 -4) ; ==> (2 -2)
(roots 1 0 -4)  ; ==> (2)
(roots 4 0 4)   ; ==> (0+1i 0-1i)