Understanding nested quotes for clojure game macro from http://lisperati.planvita.com/actions.html

I have read the tutorial "casting SPELs", its Russian version is adapted for clojure at http://lisperati.planvita.com/ ... And until this time I cannot figure out how the following macro works: (see http: // lisperati.planvita.com/actions.html for the Russian version or http://lisperati.com/actions.html for the original 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 -)))))

      

Used further:

(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 for creating the macro was to replace 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 about how this action-play macro works. Can anyone explain to me everything (nested quotes) about this?

I already read the following article - http://blog.8thlight.com/colin-jones/2012/05/22/quoting-without-confusion.html - it didn't help ...

macroexpand-1 scares me too ...

This is his result for playing in weld mode:

(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 / (clojure.core / =)) (clojure.core / list ( clojure.core / seq (clojure.core / concat (clojure.core / list (quote)) (clojure.core / list subject_1058_auto_)))) (clojure.core / list (clojure.core / seq (clojure.core / concat (clojure.core / list (quote)) (clojure.core / list (quote c hain)))))))) (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)) (clojure.core / list object_1059_auto__)))) (clojure.core / list (clojure.core / seq (clojure .core / concat (clojure.core / list (quote)) (clojure.core / list (quote bucket)))))) (clojure.core / list (clojure.core / seq (clojure.core / concat (clojure. core / list (quote clojure -magic-game. core / is there?)) (clojure.core / list (clojure.core / seq (clojure.core / concat (clojure.core / list (quote)) (clojure.core / list (quote chain))))))))))) (quote ((cond (and (is there? (quote bucket)) (def chain-welded true)) (quote (chain is now securely welded to the bucket) ): else (quote (you don't have a bucket -))))) (clojure.core / list: else) (clojure.core / list (clojure.core / seq (clojure.core / concat (clojure.core / list ( quote)) (clojure.core / (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 / -)))))))))))))))core / concat (clojure.core / list (quote)) (clojure.core / (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 / -))))))))))))))core / concat (clojure.core / list (quote)) (clojure.core / (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 you remove all namespaces and indented the output, it still looks too complex to figure out 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 -))))))))))))))

      

+3


source to share


1 answer


Don't try to learn about macros or Clojure from this.

  • Specifying an English version of Lisp

    Note how ridiculously complex this SPEL is. It has weirder quotes, backticks, commas, and other weird characters than you can shake up the list. Moreover, it's SPEL that actually threw ANOTHER SPEL! Even seasoned Lisp programmers would have to consider creating a monster like this (and in fact they would see this SPEL as inelegant and could go through some extra esoteric steps to make it more efficient so we don't worry here .. .)

    The purpose of this SPEL is to show you how smart and smart you are in these SPELs. Also, the ugliness doesn't really matter much if we only need to write it once and then use it to compose hundreds of teams for a larger adventure game.

    Translation: This is write-only rubbish. In what should be an educational introduction to the language, the author chose poor design to demonstrate an unnecessarily complex macro and wasted the opportunity to discuss intelligent use of macros and the capabilities of first-class and higher-order functions.

  • The Clojure version is transliteration, not correct translation. One example: setf

    inside a function was transliterated into def

    inside a function. This is bad Clojure.

Turn off my soapbox now

The non-confusion quote you linked is worth another reading or two.

Instead of using strings "bucket"

or keywords :bucket

, which would be more appropriate for his purpose, the author of "Casting SPELs" uses quoted characters - 'bucket

also known as (quote bucket)

.

So the author needs a macro extension like

(... (quote bucket) ...)

      

But

user=> `(... 'bucket ...)

      

has namespace qualification:

(... (quote user/bucket) ...)

      

So you end up with



user=> `(... '~'bucket ...)

      

To obtain

(... (quote bucket) ...)

      

the trick is optional ~'

, as described in the Quoting Without Confusion article .

But since the macros game-action

have nested two-digit syntax quotes, you have another layer to unwind, which means a different set~'

user=> ``(... '~'~'bucket ...)

      

The first '

is the quote

one you want, the two sets ~'

must qualify placename twice, once for each syntax quote level ``

.

This gives

(clojure.core/seq 
  (clojure.core/concat 
    (clojure.core/list (quote ...)) 
    etc...

      

Clap! But, taking Quoting Without Confusion guidelines when dealing with nested syntax quotes:

user=> (eval *1)

(... (quote bucket) ...)

      

and we see that this whole construction just gives us what we wanted.

+3


source







All Articles