2017-09-11 51 views
-1

我正在关注麻省理工学院的SICP讲座,而这正是我试图通过亚历山大方法的Heron找到一个数的平方根近似值。这是我第一次尝试lisp,很抱歉做出了noobie错误。错误:(/)错误的参数类型:#<unspecified>鸡方案平方根近似

(define guess 1) 

(define (avg a b) 
    (/ (+ a b) 2)) 

(define (try guess x) 
    (if (goodEnough guess x) 
     guess 
     (improve guess x))) 

(define (improve guess x) 
    (define guess (avg guess (/ x guess))) 
    (try guess x) 
) 

(define (goodEnough guess x) 
    (= guess (avg guess (/ x guess)))) 

(print (try 1 25)) 

我正在使用鸡计划编译器来打印此。这是输出:

Error: (/) bad argument type: #<unspecified> 

    Call history: 

    1.a.SquareRootApproximation.scm:29: try 
    1.a.SquareRootApproximation.scm:17: goodEnough  
    1.a.SquareRootApproximation.scm:27: avg 
    1.a.SquareRootApproximation.scm:19: improve  <-- 

更新时间:我已经改变了我的办法来使用LISP更抽象的这个问题,但我无法弄清楚这个新的错误想暗示什么。任何修复?谢谢!

回答

1

#<unspecified>在其他语言中基本上是“无效的”。只要某个过程没有任何有用的返回值,它就被用作返回值(例如,print将返回此值)。在某些情况下,它也用作临时占位符值,例如处理内部define时。

通常情况下,该临时占位符对语言用户而言不应该是可见的,但看起来您已经在语言中遇到了一个奇怪的边界情况(恭喜!很少发生这种情况)。发生错误是因为improve过程中的(define guess (avg guess (/ x guess)))正在同时定义一个变量并使用该变量。这样做的行为没有明确规定,一些Scheme实现将会做鸡做的事(Guile,Gauche,Gambit),而另一些会给出一个更有意义的错误信息(MIT,Scheme48,Racket)。这个错误的原因与内部define扩展到letrec这一事实有关,因为它允许定义相互递归过程,但是这会产生一些问题:例如(define a b) (define b a)应该发生什么?

你的意图似乎是使用的AS输入过程传递旧猜测变量,因此而不是使用define你可以使用let绑定一个新值guess(这个应该怎么表现是良好的规范),或只需使用不同的名称,如new-guess

+0

我还没有听说过,但我仍然在第一讲。也许新的猜测是正确的选择。谢谢。它实际上与新变量一起工作。 –

+0

这是非常明确的,因为在R5RS和早些时候在'lambda'中的'define'(和派生形式)是'letrec'不允许任何变量在body和R6RS之前被评估,并且后来它是'letrec *'这允许已经初始化的变量被评估。当然,这些都不允许评估被同一'lambda'中的任何**本地'define'遮蔽的变量。 'letrec'和'letrec *'是允许递归函数,因此绑定需要在创建闭包时存在。 – Sylwester

+0

从某种意义上讲,“直接在'”形式中提及“”的值是“错误”。但是,这基本上意味着“实现可以随意做任何事情”。本质上,它类似于C中的“未定义的行为”。任何“是一个错误”都不属于规范,导致这种错误的程序可能会或可能不会运行/编译。这是非常依赖实施的,正如你可以从我的例子看到的那样:MIT,Racket和Scheme48与CHICKEN,Guile,Gambit和Gauche的行为非常不同。 – sjamaan