Reputation: 101
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.
Upvotes: 1
Views: 3746
Reputation: 58500
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
.
Upvotes: 0
Reputation: 1446
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*))
Upvotes: 5