I have read the "casting SPELs" tutorial, its russian version adapted for clojure at http://lisperati.planvita.com/... And up to this time I can't understand how the following macro works: (see http://lisperati.planvita.com/actions.html for russian version or http://lisperati.com/actions.html for original one for Lisp):
(defspel game-action [command subj obj place & args]
`(defspel ~command [subject# object#]
`(spel-print (cond (and (= location '~'~place)
(= '~subject# '~'~subj)
(= '~object# '~'~obj)
(have? '~'~subj))
~@'~args
:else '(i cannot ~'~command like that -)))))
It is is used further like:
(game-action weld chain bucket attic
(cond (and (have? 'bucket) (def chain-welded true))
'(the chain is now securely welded to the bucket -)
:else '(you do not have a bucket -)))
(game-action dunk bucket well garden
(cond chain-welded
(do (def bucket-filled true)
'(the bucket is now full of water))
:else '(the water level is too low to reach -)))
Here defspel - is just an alias for defmacro.
The reason to create the macro was to substitue the following functions:
(defn weld [subject object]
(cond (and (= location 'attic)
(= subject 'chain)
(= object 'bucket)
(have? 'chain)
(have? 'bucket)
(not chain-welded))
(do (def chain-welded true)
'(the chain is now securely welded to the bucket -))
:else '(you cannot weld like that -)))
(defn dunk [subject object]
(cond (and (= location 'garden)
(= subject 'bucket)
(= object 'well)
(have? 'bucket)
chain-welded)
(do (def bucket-filled true)
'(the bucket is now full of water))
:else '(you cannot dunk like that -)))
I am completely confused with how this "game-action" macro works... Can anybody explain me all things (nested quotes) about it?
I have already read the following article - http://blog.8thlight.com/colin-jones/2012/05/22/quoting-without-confusion.html - it did not help...
macroexpand-1 scares me too...
This is its output for the weld game-action:
(clojure-magic-game.core/defspel weld [subject_1058_auto__ object_1059_auto_] (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure-magic-game.core/spel-print)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/cond)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/and)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/=)) (clojure.core/list (quote clojure-magic-game.core/location)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote attic)))))))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/=)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list subject_1058_auto_)))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote chain)))))))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/=)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list object_1059_auto__)))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote bucket)))))))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure-magic-game.core/have?)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote chain))))))))))) (quote ((cond (and (have? (quote bucket)) (def chain-welded true)) (quote (the chain is now securely welded to the bucket -)) :else (quote (you do not have a bucket -))))) (clojure.core/list :else) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure-magic-game.core/i)) (clojure.core/list (quote clojure-magic-game.core/cannot)) (clojure.core/list (quote weld)) (clojure.core/list (quote clojure-magic-game.core/like)) (clojure.core/list (quote clojure-magic-game.core/that)) (clojure.core/list (quote clojure.core/-))))))))))))))
Even if to remove all namespaces and indent the output It will still look too complicated to understand for me:
(defspel weld [subject__1058__auto__ object__1059__auto__]
(seq (concat
(list (quote spel-print))
(list (seq (concat
(list (quote cond))
(list (seq (concat
(list (quote and))
(list (seq (concat
(list (quote =))
(list (quote location))
(list (seq (concat
(list (quote quote))
(list (quote attic))))))))
(list (seq (concat (list (quote =))
(list (seq (concat
(list (quote quote))
(list subject__1058__auto__))))
(list (seq (concat
(list (quote quote))
(list (quote chain))))))))
(list (seq (concat
(list (quote =))
(list (seq (concat
(list (quote quote))
(list object__1059__auto__))))
(list (seq (concat
(list (quote quote))
(list (quote bucket))))))))
(list (seq (concat
(list (quote have?))
(list (seq (concat
(list (quote quote))
(list (quote chain)))))))))))
(quote ((cond
(and
(have? (quote bucket))
(def chain-welded true))
(quote (the chain is now securely welded to the bucket -))
:else (quote (you do not have a bucket -)))))
(list :else)
(list (seq (concat
(list (quote quote))
(list (seq (concat
(list (quote i))
(list (quote cannot))
(list (quote weld))
(list (quote like))
(list (quote that))
(list (quote -))))))))))))))