4

我已经在http://lisperati.planvita.com/阅读了“casting SPELs”教程,它的俄文版本适用于 clojure ...到目前为止,我无法理解以下宏是如何工作的:(参见http: //lisperati.planvita.com/actions.html用于俄语版本或http://lisperati.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://blog.8thlight.com/colin-jones/2012/05/22/quoting-without-confusion.html - 它没有帮助......

macroexpand-1 也吓到我了...

这是焊接游戏动作的输出:

(clojure-magic-game.core/defspel 焊接 [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?) bucket)) (def chain-welded true)) (quote (链条现在已牢固地焊接在水桶上 -)) :else (quote (你没有水桶 -)))))) (clojure.core/list : else) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (引用 )) (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.核心/不能))(clojure.core/list(引用焊接))(clojure.core/list(引用clojure-magic-game.core/like))(clojure.core/list(引用clojure-magic-game.core /that)) (clojure.core/list (quote 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 -))))))))))))))
4

1 回答 1

4

不要试图从中学习宏或 Clojure。

  1. 引用英文 Lisp 版本

    注意这个 SPEL 是多么的复杂——它有更多奇怪的引号、反引号、逗号和其他奇怪的符号,而不是你可以动摇的列表。不仅如此,它实际上是一个施放另一个 SPEL 的 SPEL!即使是经验丰富的 Lisp 程序员也不得不考虑创建这样的怪物(事实上,他们会认为这个 SPEL 不优雅,并且会通过一些额外的深奥步骤使其表现得更好,我们不会在这里担心...)

    这个 SPEL 的重点是向您展示使用这些 SPEL 可以变得多么复杂和聪明。此外,如果我们只需要编写一次然后可以使用它为更大的冒险游戏制作数百个命令,那么丑陋并不重要。

    翻译:这是只写垃圾。在该语言的教程介绍中,作者选择了糟糕的设计来展示一个不必要的复杂宏,并浪费了一个机会来讨论宏的明智使用以及一等函数和更高阶函数的威力。

  2. Clojure 版本是音译而不是正确的翻译。一个例子:setf函数内部被音译成def函数内部。这是糟糕的 Clojure。

现在离开我的肥皂盒

您链接到的引用没有混淆的文章值得一读或两读。

“Casting SPELs”作者没有使用更适合他的目的的字符串 ,"bucket"或关键字 ,而是使用带引号的符号 -也称为.:bucket'bucket(quote bucket)

所以作者需要一个宏扩展,比如

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

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

命名空间限定:

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

所以,你最终不得不

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

要得到

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

诀窍是额外的,如在引用没有混淆的文章~'中所解释的那样。

但是由于game-action宏作者在语法引号中嵌套了两层,因此您还有另一层要展开,这意味着另一组~'

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

第一个'quote你想要的,这两组~'是两次转义名称空间限定,每个级别的语法 quote 一次``

这产生

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

哎呀!但是在处理嵌套语法引号时,请参考Quoteing without Confusion的建议:

user=> (eval *1)

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

我们看到所有这些构造只是为了给我们想要的东西。

于 2013-02-16T20:09:28.570 回答