Error: (/) bad argument type: #<unspecified> Chicken Scheme Square root approximation

280 views Asked by At

I am following the SICP lectures from MIT, and this is what I tried to find the square root approximation of a number by Heron of Alexandria's method. This is my first time trying out lisp, sorry for making noobie mistakes.

(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))

I am using Chicken scheme compiler to print this. This is the output:

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

Updated: I have changed my approach towards this problem using lisp with more abstraction, yet I can't figure out what this new error wants to imply. Any fixes? Thanks!

1

There are 1 answers

3
sjamaan On BEST ANSWER

The value #<unspecified> is basically "void" in other languages. It is used as a return value whenever some procedure has nothing useful to return (for example, print will return this). It is also in some situations used as a temporary placeholder value, for example when handling an inner define.

Normally this temporary placeholder should not be visible to the user of the language, but it appears you've hit a strange edge case in the language (congratulations! This happens rarely). The error happens because (define guess (avg guess (/ x guess))) in the improve procedure is simultaneously defining a variable and using that variable. The behaviour of doing this is not well-specified, and some Scheme implementations will do what CHICKEN is doing (Guile, Gauche, Gambit) whereas others will give a somewhat more meaningful error message (MIT, Scheme48, Racket). The reason this is ill-specified has to do with the fact that inner define expands to letrec, because it allows mutually recursive procedures to be defined, but that creates a bit of an issue: what should happen for (define a b) (define b a), for example?

Your intention seems to be using the old guess variable that's passed as input to the procedure, so instead of using define you could use let to bind a new value for guess (how this should behave is well-specified), or just use a different name for it, like new-guess.