Rewriting Wizard game of Land of Lisp in Clojure
Asked Answered
D

2

9

I'm trying to rewrite the Wizard game from "Land of Lisp" http://landoflisp.com/wizards_game.lisp

(def *nodes* {:living-room "you are in the living-room. a wizard is snoring loudly on the couch."
          :garden "you are in a beautiful garden. there is a well in front of you."
          :attic "you are in the attic. there is a giant welding torch in the corner."})

(def *edges* {:living-room '((garden west door) (attic upstairs ladder))
          :garden '(living-room east door)
          :attic '(living-room downstairs ladder)})

(defn describe-location [location nodes]
  (nodes location))

(defn describe-path-raw [edge]
  `(there is a ~(last edge) going ~(second edge) from here.))

(defn describe-path [edge]
   (map #(symbol (name %)) (describe-path-raw edge)))

(defn describe-paths [location edges]
   (apply concat (map describe-path-raw (location edges))))

When trying:

   (println (describe-paths :attic *edges*))

I got this exception:

Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol (wizard-game.clj:0)

I don't have a Lispy eye yet, what I'm doing wrong?

Domoniquedomph answered 19/3, 2011 at 16:47 Comment(0)
S
8

Putting this into a REPL, and running trace:

user> (ns foo (:use clojure.contrib.trace))
nil

At this point I copy in your code into the REPL. (not shown)

Next, I run a trace:

foo> (dotrace [describe-location describe-path-raw describe-path describe-paths]
              (describe-paths :attic *edges*))
TRACE t1662: (describe-paths :attic {:living-room ((garden west door) (attic upstairs ladder)),     :garden (living-room east door), :attic (living-room downstairs ladder)})
TRACE t1663: |    (describe-path-raw living-room)
; Evaluation aborted.
foo> 

So the problem is (describe-path-raw living-room). As the error message points out, living-room is a symbol, and this function is trying to do things like call last and second on it, which can only be done on sequences.

So why is this happening?

Inside of describe-paths, you are calling (location edges). Here, location is :attic, and edges is a map. Therefore, (location edges) works out to (living-room downstairs ladder). You are mapping describe-path-raw onto this list, which works out to:

((describe-path-raw living-room) (describe-path-raw downstairs) (describe-path-raw ladder))

And this is throwing an exception on the first call, since living-room is a symbol, not a sequence.

Squat answered 19/3, 2011 at 17:16 Comment(4)
Why the call is becoming: (describe-path-raw living-room) ? :attic has value of list type.Domoniquedomph
@4bu3li: See the addition to my answer. I hope this helps.Squat
attic is mapped to a list. I mean this is a list, right? '(living-room downstairs ladder) ? I run this code: (class (:attic '(living-room downstairs ladder))) which returns PersistentList. I solved the issue, thanks to you and seh but I still didn't get the real problem.Domoniquedomph
@4bu3li: That is a list, correct. It is returned by (location edges), inside of the describe-paths function. But then describe-paths calls map describe-path-raw onto that list. What does that do? It applies describe-path-raw onto every element in that list. The first element in that list is living-room, and therefore, the first function call for evaluating (map describe-path-raw living-room) is (describe-path-raw living-room). And living-room is a symbol, which is not what describe-path-raw requires.Squat
T
1

It looks like describe-paths expects that the value looked up in the *edges* map will be a list of lists, not just a list. Note the difference between the :living-room entry and the :garden and :attic entries: the former has a top-level spine below which you find two three-tuples, whereas the latter two each have just one three-tuple.

Function describe-path-raw expects to receive a tuple of at least size two, but it really only makes sense here for those of size three; feeding it any of the four three-tuples in the *edges* map will work. The problem you ran into is due to applying map to the *edges* entry for :attic, which takes the list

(living-room downstairs ladder)

and feeds the list objects one-by-one to describe-path-raw:

(describe-path-raw living-room)
(describe-path-raw downstairs)
(describe-path-raw ladder)

In each of those three forms, the argument passed to describe-path-raw is a symbol, rather than the list expected by describe-path-raw.

In short, try adding an extra set of parentheses around the second two values in your *edges* map, nesting each list within a new top-level list.

Trident answered 19/3, 2011 at 21:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.