2013-07-06 3 views
1

Я пробую свою руку в текстовом приключении в clojure.Доступ к глобальной переменной по ее названию в Clojure

Это где я борюсь:

(ns records) 


(defrecord Room [fdesc sdesc ldesc exit seen]) 

(defrecord Item [name location adjective fdesc ldesc sdesc flags action ]) 

(def bedroom (Room. "A lot of text." 
        nil 
        "some text" 
        '(("west" hallway wearing-clothes? wear-clothes-f)) 
        false)) 

(def hallway (Room. "description of room." 
          nil 
          "short desc of room." 
          '(("east" bedroom) ("west" frontdoor)) 
          false)) 

(def location (ref bedroom)) 

(defn in? 
    "Check if sequence contains item." 
    [item lst] 
    (some #(= item %) lst)) 

(defn next-location 
    "return the location for a entered direction" 
    [direction ] 
    (second (first (filter #(in? direction %) (:exit @location))))) 

(defn set-new-location 
    "set location parameter to new location." 
    [loc] 
    (dosync (ref-set location loc))) 

Моя проблема с обновлением местоположения вар.

Если я вхожу (set-new-location hallway), он работает правильно. Местоположение установлено в новом помещении, и я могу получить доступ к его полям. Однако мне нужно прочитать следующий возможный выход из поля выхода комнаты, но когда я вхожу в (set-new-direction (next-exit "west")), местоположение говорит о коридоре, но оно не указывает на переменную «коридор».

В CL я бы использовал (коридор с символикой). Как я могу сделать это в Clojure?

EDIT: Я действительно хочу использовать var-per-location, потому что я набросал примерно 30 местоположений по 20 строк каждый, что делает его слишком громоздким для размещения на одной карте.

ответ

3

Вы можете использовать @(resolve sym) как symbol-value workalike; то, что он на самом деле делает, это искать Var, названный символом sym в текущем пространстве имен (может быть, Var внесено с use/require :refer) и извлечь его значение. См ns-resolve, если вы хотите, чтобы контролировать пространство имен Вар ищется в

Вы также можете не использовать Var-за местоположения, а хранить свои места в карте где-то:.

(def locations {:hallway ... :bedroom ...}) 

(You также мог бы поместить эту карту в Ref для удобства добавления новых мест во время выполнения.)

+0

Как это должно работать? Если я попробую '(ref-set location @ (разрешить спальню))' I get 'ClassCastException records.Room не может быть добавлен в clojure.lang.Symbol clojure.core/ns-resolve (core.clj: 3954)'. – martin

+0

Вам нужно будет сказать '@ (разрешить« спальню »' (обратите внимание на цитату), чтобы передать символ 'спальня' для' разрешения'. Конечно, если у вас есть какой-то конкретный символ, нет смысла делать это, и вы можете просто написать «спальня»; но если символ динамически вычисляется, например, при вызове 'next-location', то никакое дополнительное цитирование не понадобится:' @ (resolve (next-location «west»)). –

Смежные вопросы