5

私は次のマクロをlispの土地からclojureに変換しようとしています:

(defmacro tag (name atts &body body)
  `(progn (print-tag ',name
                     (list ,@(mapcar (lambda (x)
                                       `(cons ',(car x) ,(cdr x)))
                                     (pairs atts)))
                     nil)
          ,@body
          (print-tag ',name nil t)))

しかし、私はもう1つのレベルの評価を必要とするattsで立ち往生し続けています。たとえば、次のようにt#を評価する必要があります。

(defmacro tag [tname atts & body]
  `(do (print-tag '~tname '[~@(map (fn [[h# t#]] [h# t#]) (pair atts))] nil)
     ~@body
     (print-tag '~tname nil true)))

それは次のようなものを生成するので:

(tag mytag [color 'blue size 'big])
<mytag color="(quote blue)" size="(quote big)"><\mytag>

属性を評価したい場所。上記で「(evalt#)」を使用すると、次のような問題が発生します。

(defn mytag [col] (tag mytag [colour col]))
java.lang.UnsupportedOperationException: Can't eval locals (NO_SOURCE_FILE:1)

助言がありますか?

Clojureで評価のレベルが1つ下がったように見えるのはなぜですか?

サポート機能の定義:

;note doesn't handle nils because I'm dumb
(defn pair [init-lst]
      (loop [lst init-lst item nil pairs []]
    (if (empty? lst)
      pairs
      (if item
        (recur (rest lst) nil (conj pairs [item (first lst)]))
        (recur (rest lst) (first lst) pairs)))))

(defn print-tag [name alst closing]
      (print "<")
      (when closing
    (print "\\"))
      (print name)
      (doall
      (map (fn [[h t]]
           (printf " %s=\"%s\"" h t))
       alst))
      (print ">"))

(何らかの理由で、本と同じようにペア関数を実行しなかったため、nilsが正しく処理されません)

4

3 に答える 3

4

Clojureの定義でtagは、属性マップ内のすべてが引用されますが、一般的なlispバージョンでは名前のみが引用されます。これが問題の直接の原因です'。ベクター/マップの前にをドロップしmap、最初の要素を引用するためにをいじった場合は、おそらく問題ありません。

ただし、移植は良い練習になるかもしれませんが、このコードはThe Clojure Wayで書かれていません。印刷は厄介な副作用であり、print-tagを使用して意味のあることを行うのは困難です。代わりに文字列を返す方がはるかに便利です。

(defmacro tag [name attrs & body]
  `(str "<" 
        (clojure.string/join " "
                             ['~name
                              ~@(for [[name val] (partition 2 attrs)]
                                  `(str '~name "=\"" ~val "\""))])
        ">"
        ~@body
        "</" '~name ">"))

user> (tag head [foo (+ 1 2)] "TEST" (tag sample []))
"<head foo=\"3\">TEST<sample></sample></head>"

もちろん、順序は重要ではないため、属性にはベクトルの代わりにマップを使用する方が適切です。(partition 2...)これは、マップのシーケンシャルビューがすでにペアとして表示されているため、を削除できることも意味します。

そして、ここまで到達すると、XMLをClojureデータ構造として表現する方法はすでにたくさんあることがわかりました。そのため、実際のアプリケーションで上記のコードを使用することは決してありません。XMLを実際に実行したい場合は、Hiccupprxml、またはdata.xmlのいずれかを確認してください。

于 2011-08-06T21:53:40.107 に答える
0

私は何かが足りないかもしれませんが、色とサイズではなく青と大きなものを引用した特別な理由があります。また、ベクトルの周りに引用符をドロップすると、その中のものが評価されないように、マクロでベクトルを引用しました。引用色と大きなあなたはあなたが望むものを手に入れます、


(defmacro tag [tname atts & body]
  `(do (print-tag '~tname [~@(map (fn [[h# t#]] [h# t#]) (pair atts))] nil)
       ~@body
       (print-tag '~tname nil true)))

(tag mytag ['color 'blue 'size 'big])

<mytag color="blue" size="big"><\mytag>nil

キーワードを使用する記号の代わりに記録のためだけに、これにはより慣用的なclojureがあります。

于 2011-08-06T18:49:18.820 に答える
0

完全を期すために、私が望んでいたのは次のとおりです。

(defmacro tag [tname atts & body]
  `(do (print-tag '~tname [~@(map (fn [[h# t#]] [`'~h# t#]) (pair atts))] nil)
     ~@body
     (print-tag '~tname nil true)))
于 2011-08-06T22:20:41.240 に答える