Casting SPELs



Now we're going to learn an incredibly powerful feature of Lisp: Creating SPELs!

SPEL is short for "Semantic Program Enhancement Logic" and lets us create new behavior inside the world of our computer code that changes the Lisp language at a fundamental level in order to customize its behavior for our needs- It's the part of Lisp that looks most like magic. To enable SPELs, we first need to activate SPELs inside our Lisp compiler (Don't worry about what this line does- Advanced Lispers should click here.)

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

Ok, now that they're enabled, let's cast our first spell, called walk:

(defspel walk (direction)
  `(walk-direction ',direction))

What this code does is it tells the Lisp compiler that the word walk is not actually the word walk but the word walk-direction and that the word direction actually has a quote in front of it, even though we can't see it. Basically we can sneak in some special code inbetween our program and the compiler that changes our code into something else before it is compiled:





Notice how similar this function looks to the code we had written before for describe-path: In Lisp, not only do code and data look a lot identical, but code and special commands to the compiler (the SPELs) look identical as well- A very consistent and clean design! Let's try our new spell:


(walk east)
==> (YOU ARE IN THE LIVING ROOM OF A WIZARD'S HOUSE.
THERE IS A WIZARD SNORING LOUDLY ON THE COUCH.
THERE IS A DOOR GOING WEST FROM HERE.
THERE IS A STAIRWAY GOING UPSTAIRS FROM HERE.
YOU SEE A WHISKEY-BOTTLE ON THE FLOOR.
YOU SEE A BUCKET ON THE FLOOR)

much better!

Now we'll create a command to pickup objects in our world:

(defun pickup-object (object) (cond ((is-at object *location* *object-locations*) (push (list object 'body) *object-locations*) `(you are now carrying the ,object)) (t '(you cannot get that.))))

This function checks to see if the object is indeed on the floor of the current location- If it is, it pushes the new location (the player's body) onto the list (pushing means to add a new item to the list, in a way that the assoc command sees and therefore hides the previous location) and returns a sentence letting us know wether it succeeded.

Now let's cast another SPEL to make the command easier to use:

(defspel pickup (object)
  `(pickup-object ',object))

Now let's try our new SPEL:


(pickup whiskey-bottle)
==> (YOU ARE NOW CARRYING THE WHISKEY-BOTTLE)
Now let's add a couple more useful commands- First, a command that lets us see our current inventory of items we're carrying:

(defun inventory () (remove-if-not (lambda (x) (is-at x 'body *object-locations*)) *objects*))

Now a function that tells us if he have a certain object on us:

(defun have (object) (member object (inventory)))

<< PREVIOUS                 NEXT >>