2
votes

I'm receiving the error variable MAP has no value in my Common Lisp code (I am using the clisp shell in the Ubuntu terminal). My code looks like this (*map* is just an association list, so you can skip over it):

(setf *map* '((shore (stars cast reflections on the rippling sea.  
                            it fills you with a strong but unplaceable emotion.) 
                     (east forest))
              (forest (a roof of treetops blots out the sun.  something rustles 
                         behind you.) 
                      (west shore) 
                      (north cliff))
              (cliff (you nearly stumble into a long and fatal fall into the 
                          sea far below you.  you feel a strange urge to throw 
                          yourself off the ledge.  it would probably wisest to 
                          leave this place.) 
                     (south forest))))

(defun walk-direction (direction room map)
  (second (assoc direction (cddr (assoc room map)))))

(defmacro defspel (&rest rest) `(defmacro ,@rest))

(defspel walk-to (direction room map)
  `(walk-direction ',direction ',room map))

(walk-to east shore *map*)

(I'm following the liserpati tutorial, for those wondering about any oddities I might be committing)

If change walk-to to

(defspel walk-to (direction room)
  `(walk-direction ',direction ',room *map*))

then everything goes perfectly well. However, this breaks the beautiful convention of functional programming which I would like to keep as intact as possible-- not to mention the fact that I still have no idea why my code doesn't work.

2
I think he just wasn't sure how to format it. Max, don't use <code> tags, etc. Just paste in your plain code, highlight it, and press the {} toolbar button, which will tab it over into a code block.ooga

2 Answers

6
votes

The definition of walk-to is missing a comma before map. Take a look at the output of:

(macroexpand-1 '(walk-to east shore *map*))
0
votes

Let's take a look at:

(defspel walk-to (direction room map)
  `(walk-direction ',direction ',room map))

Here, the symbol map is inside a backquote, and it isn't unquoted. This means that it is just a literal datum. It has no connection to the map argument of the walk-to spell.

The generated walk-direction code evaluates in an environment in which the map argument is no longer visible; it is treated as a free variable reference which expects a global variable to exist.

When you change map to *map* you fix part of the problem; the generated code then refers to the dynamic variable *map* in the global environment.

But this is still broken, because walk-to is supposed to generate code which uses the map which is passed in, which is not necessarily the global map (or else why have a parameter).

You probably want this:

(defspel walk-to (direction room map)
  `(walk-direction ',direction ',room ,map))

So that, for instance, the call (walk-to north shore *map*) will generate the code (walk-direction 'north 'shore *map*). The walk-to macro quotes the direction and room symbols for you, but should not quote *map*, since that is Lisp variable which we need to evaluate to the map object it represents, and not a game symbol like north.