views:

199

answers:

3

I decided to learn LISP today, and have been playing around with it for a bit. I wrote a simple baby function just to test my understanding, and now understand that my understanding doesn't understand as much as I had understood it to understand. :D

Anyway, here is the function. The idea is that when it is called, e.g. (esexp base x) it should return the value base^x. So (esexp 3 4) = 3^4 = 81.

(I am using the CMU implementation of Common Lisp, if that matters.)

(defun esexp (base x)
  (if (= x 0)
      1
      (if (< x 0)
          (/ esexp (base (+ x 1)) base)
          (* esexp (base (+ x 1)) base))))

This doesn't work. I get errors that look like (Warning: This variable is undefined: SLBEXP) and (Error in KERNEL::UNBOUND-SYMBOL-ERROR-HANDLER: the variable SLBEXP is unbound.) So. What am I doing wrong? AND would there be a better (or more LISP-ish way) to write this function?

ETA

Corrected code:

(defun esexp (base x)
  (if (= x 0)
      1
      (if (< x 0)
          (/ (esexp base (+ x 1)) base) 
          (* (esexp base (- x 1)) base))))
+11  A: 

esexp(base (+ x 1))

should be

(esexp base (+ x 1))

esexp is a function just like +. The syntax for invoking a function is

(function-name arg1 arg2 ...)
sigjuice
Ah duh. Thanks.
Asker
A: 

Just a note about the code. I believe it should be

(defun esexp (base x)
        (if (= x 0)
                1
                (if (< x 0)
                        (/ (esexp(base (+ x 1)) base))
                        (* (esexp(base (- x 1)) base))))

Otherwise the function will never terminate. (you had (* (esexp(base (+ x 1)) base)))))

Jamie Wong
Also, thanks. That was an error in transcription.
Asker
+4  A: 

The technical explanation of the error: the compiler was parsing the code:

(/ esexp(base (+ x 1)) base)

as this:

(/ esexp (base (+ x 1)) base)

which says:

  • first, add 1 to the parameter x
  • then, invoke a function called base with the result above.
  • divide the value of a variable called esexp by the result above.
  • then, divide that result by the parameter base. (The divide operator in Common Lisp can take more than two arguments.)

You see the trick? When a word appears as the first item in a s-expression (and that s-expression isn't quoted), it's usually treated as the name of a function you want to invoke. Otherwise, it's treated as the name of a variable whose value you want to retrieve. Further, in Common Lisp a symbol like esexp can be bound to both a function value and a variable value at the same time; context or special expressions like #'esexp (which means the function) are used to figure out which one you mean.

The compiler was telling you that, though esexp was bound to a function with your defun statement, it had not yet been bound to a variable value, and therefore could not be used as such. Hence, the error.

Owen S.