我的代码表示错误“应用程序:不是程序”或“调用非程序”

问题描述 投票:6回答:1

在执行我的代码期间,我在不同的Scheme实现中遇到以下错误:

球拍:

application: not a procedure;
 expected a procedure that can be applied to arguments
  given: '(1 2 3)
  arguments...:

的Ikarus:

Unhandled exception
 Condition components:
   1. &assertion
   2. &who: apply
   3. &message: "not a procedure"
   4. &irritants: ((1 2 3))

鸡:

Error: call of non-procedure: (1 2 3)

开局:

*** ERROR IN (console)@2.1 -- Operator is not a PROCEDURE
((1 2 3) 4)

WITH Scheme:

;The object (1 2 3) is not applicable.
;To continue, call RESTART with an option number:
; (RESTART 2) => Specify a procedure to use in its place.
; (RESTART 1) => Return to read-eval-print level 1.

在Scheme:

Exception: attempt to apply non-procedure (1 2 3)
Type (debug) to enter the debugger.

诡计:

ERROR: In procedure (1 2 3):
ERROR: Wrong type to apply: (1 2 3)

χ比:

ERROR in final-resumer: non procedure application: (1 2 3)
scheme runtime-error racket
1个回答
9
投票

Why is it happening

Scheme过程/函数调用如下所示:

(operator operand ...)

运算符和操作数都可以是test+等变量,它们可以计算出不同的值。对于过程调用来说,它必须是一个过程。从错误消息看,test似乎不是一个程序,而是列表(1 2 3)

表单的所有部分也可以是表达式,因此像((proc1 4) 5)这样的语法是有效的语法,并且预期调用(proc1 4)返回一个过程,然后使用5作为唯一参数调用该过程。

Common mistakes that produces these errors.

尝试对表达式进行分组或创建块

(if (< a b)
    ((proc1)
     (proc2))
    #f)

当谓词/测试为真时,Scheme假设将尝试评估(proc1)(proc2),然后由于括号,它将调用(proc1)的结果。要在Scheme中创建块,请使用begin

(if (< a b)
    (begin 
      (proc1)
      (proc2))
    #f)

在这个(proc1)被称为只是为了效果和teh形式的结果将是最后一个表达式(proc2)的结果。

影子程序

(define (test list)
  (list (cdr list) (car list)))

这里的参数叫做list,这使得list程序在调用期间不可用。一个变量只能是Scheme中的过程或不同的值,最接近的绑定是您在操作符和操作数位置获得的绑定。这将是普通的Lispers所犯的典型错误,因为在CL中他们可以使用list作为参数而不会弄乱函数list

cond中包装变量

(define test #t) ; this might be result of a procedure

(cond 
  ((< 5 4) result1)
  ((test) result2)
  (else result3))

虽然除了谓词表达式(< 5 4) (test)看起来正确,因为它是一个检查thurthness的值,它与else术语有更多的共同点,并且应该像这样写:

(cond 
  ((< 5 4) result1)
  (test result2)
  (else result3))

应该返回过程的过程并不总是如此

由于Scheme不强制执行返回类型,因此您的过程可以在一种情况下返回一个过程,在另一种情况下返回非过程值。

(define (test v)
  (if (> v 4) 
      (lambda (g) (* v g))
      '(1 2 3)))

((test 5) 10) ; ==> 50
((test 4) 10) ; ERROR! application: not a procedure

未定义的值,如#<void>#!void#<undef>#<unspecified>

这些通常是由变形形式返回的值,如set!set-car!set-cdr!define

(define (test x)
  ((set! f x) 5))

(test (lambda (x) (* x x)))

这个代码的结果是不确定的,因为set!可以返回任何值,我知道一些方案实现,如MIT Scheme实际上返回绑定值或原始值,结果将是2510,但在许多实现中,你得到一个常量值,如#<void>,因为它不是一个程序,你会得到同样的错误。依赖于一种在规范下使用的实现方法,可以为您提供不可移植的代码。

以错误的顺序传递参数

想象一下,你有这样的功能:

(define (double v f)
  (f (f v)))

(double 10 (lambda (v) (* v v))) ; ==> 10000

如果你错误地交换了参数:

(double (lambda (v) (* v v)) 10) ; ERROR: 10 is not a procedure

在更高阶函数中,例如foldmap,不按正确顺序传递参数将产生类似的错误。

尝试像Algol派生语言一样申请

在algol语言中,比如JavaScript和C ++,当尝试使用fun参数应用arg时,它看起来像:

fun(arg)

这被解释为Scheme中的两个独立表达式:

fun   ; ==> valuates to a procedure object
(arg) ; ==> call arg with no arguments

使用fun作为参数应用arg的正确方法是:

(fun arg)

多余的括号

这是一般的“抓住所有”其他错误。像((+ 4 5))这样的代码在Scheme中不起作用,因为这个表达式中的每组括号都是一个过程调用。你根本无法添加任意多个,因此你需要保持它(+ 4 5)

Why allow these errors to happen?

操作员位置的表达式允许将变量作为库函数调用,为语言赋予了表达能力。这些是你习惯的时候会喜欢的功能。

这是abs的一个例子:

(define (abs x)
  ((if (< x 0) - values) x))

这在(- x)(values x)(返回其参数的标识)之间切换,你可以看到它调用表达式的结果。以下是使用cps的copy-list示例:

(define (copy-list lst)
  (define (helper lst k)
    (if (null? lst)
        (k '())
        (helper (cdr lst)
                (lambda (res) (k (cons (car lst) res))))))
  (helper lst values))

请注意,k是一个我们传递函数的变量,它被称为函数。如果我们传递的不是其他任何东西,那么你会得到同样的错误。

Is this unique to Scheme?

一点也不。所有具有一个可以将函数作为参数传递的命名空间的语言都会遇到类以下是一些类似问题的JavaScript代码:

function double (f, v) {
  return f(f(v));
}

double(v => v * v, 10); // ==> 10000
double(10, v => v * v);
; TypeError: f is not a function
;     at double (repl:2:10)

// similar to having extra parentheses 
function test (v) {
  return v;
}

test(5)(6); // == TypeError: test(...) is not a function

// But it works if it's designed to return a function:
function test2 (v) {
  return v2 => v2 + v;
}

test2(5)(6); // ==> 11
© www.soinside.com 2019 - 2024. All rights reserved.