【问题标题】:My code signals the error "application: not a procedure" or "call to non procedure"我的代码发出错误信号“应用程序:不是过程”或“调用非过程”
【发布时间】:2018-01-02 17:00:47
【问题描述】:

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

球拍:

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

伊卡洛斯:

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)

麻省理工学院计划:

;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.

Chez 计划:

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)

【问题讨论】:

  • @LeifAndersen 我实际上使用了(test 4),其中test 绑定到(1 2 3),但选择不包含它,因为除了它不是一个程序之外它并不重要:-)
  • 哦,好的,我将撤消该编辑。 :)
  • 嘿,矮胖猫!我看到你给了a fulsome answer here。不幸的是,问题作者是个忘恩负义的人,并删除了他们的帖子,并带走了您的答案。是否值得我们再次重新发布问题,以便您的答案可以重新发布?我对Scheme一无所知,所以我不知道这对未来的读者是否有用。
  • 好的,谢谢 - 在英国这里不是假期,但明天是周末,所以这样就可以了。祝您假期和周末快乐!

标签: runtime-error scheme racket non-procedure-application


【解决方案1】:

为什么会这样

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

(operator operand ...)

运算符和操作数都可以是变量,例如 test+,它们的计算结果不同。要使过程调用起作用,它必须是一个过程。从错误消息来看,test 似乎不是一个过程,而是列表(1 2 3)

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

产生这些错误的常见错误。

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

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

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

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

在此(proc1) 被调用只是为了生效,形式的结果将是最后一个表达式(proc2) 的结果。

阴影处理

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

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

cond中包装变量

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

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

虽然除了谓词表达式(&lt; 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

未定义的值,例如 #&lt;void&gt;#!void#&lt;undef&gt;#&lt;unspecified&gt;

这些通常是由 set!set-car!set-cdr!define 等变异形式返回的值。

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

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

这段代码的结果是不确定的,因为set! 可以返回任何值,我知道一些方案实现,如 MIT 方案实际上返回绑定值或原始值,结果将是 @987654359 @ 或 10,但在许多实现中,您会得到一个常量值,例如 #&lt;void&gt;,因为它不是一个过程,所以您会得到相同的错误。依靠在规范下使用的一种实现方法会为您提供不可移植的代码。

以错误的顺序传递参数

想象一下你有这样一个函数:

(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 派生语言中应用

在 JavaScript 和 C++ 等算法语言中,当尝试应用 fun 和参数 arg 时,它看起来像:

fun(arg)

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

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

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

(fun arg)

多余的括号

这是一般的“包罗万象”的其他错误。像((+ 4 5)) 这样的代码在Scheme 中不起作用,因为这个表达式中的每组括号都是一个过程调用。您根本无法添加任意数量,因此您需要保留它(+ 4 5)

为什么允许这些错误发生?

运算符位置的表达式并允许将变量作为库函数调用,从而赋予语言表达能力。这些是您习惯后会喜欢的功能。

这里是abs的例子:

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

这在(- x)(values x)(返回其参数的标识)之间切换,正如您所见,它调用了表达式的结果。下面是copy-list 使用 cps 的示例:

(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 是一个变量,我们将其传递给函数,并且它被作为函数调用。如果我们在那里传递除函数之外的任何其他内容,您将得到相同的错误。

这是 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

【讨论】:

  • 函数copy-list没有返回值!我对程序“价值”的理解不够,无法更正它。
  • @GeorgFuss 在单个参数调用中,它的工作方式与身份函数(lambda (v) v) 相同。 Scheme 的哪个实现有一个不工作的values
  • 很棒的工作!我见过的最好的答案之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
  • 1970-01-01
相关资源
最近更新 更多