2017-09-11 68 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