我已经阅读了“cast SPELs”教程,它的俄语版本适用于http://lisperati.planvita.com/的clojure ......到目前为止,我无法理解以下宏的工作方式:(见{{3} }对于俄语版本或http://lisperati.planvita.com/actions.html对于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 -)))))
进一步使用如下:
(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 -)))
这里的defspel - 只是defmacro的别名。
创建宏的原因是替换以下函数:
(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 -)))
我对这个“游戏动作”宏如何运作完全感到困惑......任何人都能解释一下它(嵌套引号)吗?
我已经阅读了以下文章 - http://lisperati.com/actions.html - 它没有帮助......
macroexpand-1也吓到我了......
这是焊接游戏动作的输出:
(clojure-magic-game.core / defspel weld [subject_ 1058 _auto__ object_ 1059 _auto_ ](clojure.core / seq(clojure.core / concat(clojure.core / list(引用clojure-magic-game.core / spel-print))(clojure.core / list(clojure.core / seq(clojure.core / concat)(clojure.core / list(引用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(引用桶))))))))(clojure.core / list(clojure.core / seq(clojure.core / concat(clojure.core / list(引用clojure-magic-game.core / have?))(clojure .core / list(clojure.core / seq(clojure.core / concat(clojure.core / list(quote quote))())))))))))(引用( (cond(和?) (报价桶))(def链焊接真))(报价(链现在安全焊接到桶 - )):否(引用(你没有一个桶 - )))))(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(引用clojure-magic-game.core / i))(clojure.core / list(引用clojure-magic-game.core /不能))(clojure.core / list(quote weld)) (clojure.core / list(引用clojure-magic-game.core / like))(clojure.core / list(引用clojure-magic-game.core / that))(clojure.core / list(引用clojure.core / - ))))))))))))))
即使删除所有名称空间并缩进输出它仍然看起来太复杂了,不能理解我:
(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 -))))))))))))))
答案 0 :(得分:3)
不要试图从中了解宏或Clojure。
引用英文Lisp版本
请注意这个SPEL是多么复杂 - 它有更多奇怪的引号,反引号,逗号和其他奇怪的符号,而不是你可以动摇列表。更重要的是,SPEL实际上是另一个SPEL!即使是经验丰富的Lisp程序员也不得不考虑创造一个像这样的怪物(实际上他们会认为这个SPEL是不优雅的,并会经历一些额外的深奥步骤,使它表现得更好,我们不会在这里担心...)
这个SPEL的目的是向您展示使用这些SPEL可以获得多么复杂和聪明。此外,如果我们只需要编写一次然后可以使用它为更大的冒险游戏制作数百个命令,那么丑陋并不重要。
翻译:这是只写垃圾。作为该语言的教程介绍,作者选择了糟糕的设计,以展示一个不必要的复杂宏,并浪费了一个讨论宏的明智使用和一阶和更高阶函数的力量的机会。 / p>
Clojure版本是音译而不是正确的翻译。一个例子:函数内的setf
被音译成函数内的def
。这是不好的Clojure。
现在离开我的肥皂盒
您链接的Quoting Without Confusion文章值得另读一两个。
“Casting SPELs”作者使用带引号的符号 - "bucket"
,而不是使用字符串,:bucket
或关键字'bucket
,这更适合他的目的。称为(quote bucket)
。
因此作者需要像
这样的宏扩展(... (quote bucket) ...)
但是
user=> `(... 'bucket ...)
进行名称空间限定:
(... (quote user/bucket) ...)
所以,你必须
user=> `(... '~'bucket ...)
获取
(... (quote bucket) ...)
诀窍是Quoting Without Confusion文章中解释的额外~'
。
但是,由于game-action
宏作者嵌套了两个深度的语法引号,您还有另一个要展开的图层,这意味着另一组~'
user=> ``(... '~'~'bucket ...)
第一个'
是您想要的quote
,两组~'
将两次转义名称空间限定,每个级别的语法引用``
一次
这会产生
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote ...))
etc...
糟糕!但在处理嵌套语法引用时,请考虑Quoting Without Confusion的建议:
user=> (eval *1)
(... (quote bucket) ...)
我们看到所有这些构造只是为了给我们想要的东西。