tags:

views:

183

answers:

3

I am new to lisp and am writing a few simple programs to get more familiar with it. One of the things I am doing is writing a recursive and iterative version of a factorial method. However, I have come across a problem and can't seem to solve it.

I saw a similar error at http://stackoverflow.com/questions/1187262/lisp-char-is-neither-declared-nor-bound but a solution wasn't actually reached, other than the OP realized he made a "typing mistake". In the REPL I can use the setf function and it works fine. I am also using LispBox with emacs. I would appreciate any suggestions!

(defun it-fact(num)
  (setf result 1)
  (dotimes (i num)
    (setf result (* result (+ i 1)))
  )
)

WARNING in IT-FACT : RESULT is neither declared nor bound, it will be treated as if it were declared SPECIAL.

+5  A: 

You need to bind the variable 'result' - using 'let', for example - before starting to use it:

(defun it-fact(num)
  (let ((result 1))
    (dotimes (i num)
      (setf result (* result (+ i 1))))))

For futher details you might want to read this ...

Johan Kullbom
Oh I see. I had tried 'let' before as well but I was using it as if it were setf, and I didn't include the dotimes loop inside the parenthesis of the let. I guess that has to do with scope or something. Thanks for the help everyone!
Aaron
Seriousy, indent your code properly.
Luís Oliveira
Since I'm primarily a java programmer, you can easily see why I brought down the parenthesis (viewing them as nothing more than brackets). I've since gotten used to putting the closing parenths on one line thanks to the examples presented here, so it's "seriously" not that big of a deal. Thanks anway :)
Aaron
+4  A: 

In Lisp, local variables must be explicitly declared with LET or other forms that create local variables. That differs from e.g. Python or JavaScript where assignment to variable creates the variable in current lexical scope.

Your example can be rewritten like this:

(defun it-fact(num)
  (let ((result 1))
    (dotimes (i num)
      (setf result (* result (+ i 1))))))

An off-topic comment: there is no point in putting closing parentheses on separate lines.

dmitry_vk
+6  A: 

There are a few things wrong or not so good Lisp style:

(defun it-fact(num)                      ; style: use a space before (
  (setf result 1)                        ; bad: variable result is not introduced
  (dotimes (i num)
    (setf result (* result (+ i 1)))     ; bad: extra addition in each iteration
  )                                      ; style: parentheses on a single line
)                                        ; bad: no useful return value

A possible version:

(defun it-fact (num)
  (let ((result 1))                      ; local variable introduced with LET
    (loop for i from 1 upto num          ; i starts with 1, no extra addition
      do (setf result (* result i)))
    result))                             ; result gets returned from the LET
Rainer Joswig
Thanks for the suggestions! Yeah, I realized that dotimes started from 0 and if I didn't increment it in the multiplication it would always return 0...Your loop does look easier to read. I think I put parenthesis on every line like that because I'm still used to braces from c++/java, but I will try to adopt your practice for lisp. Oops, yeah, I overlooked the return, thanks for pointing these things out!
Aaron