5

私がフォームの式を持っていることを考えると

'(map? %)

どうすればそれを次のようなものに変換できますか

'#(map? %)

最終的に次のようなものに拡張できるように

'(apply #(map? %) value)

何らかの方法でマクロを使用する必要があると思いますが、方法がわかりません。

4

2 に答える 2

6

リーダー マクロの#呼び出しとリーダー マクロの展開は、通常のマクロ展開が発生する前に発生します。したがって、あなたが言及したことを行うには、read-string以下に示すようにマクロでリーダーを通過する必要があります。

(defmacro pred [p v] 
     (let [s# (str \# (last p))] 
         `(apply ~(read-string s#) ~v)))



user=> (pred '(map? %) [{}])
true
user=> (pred '(map? %) [[]])
false

データ、つまり述語式が実行時に利用できる場合は、関数を使用する必要があります (マクロよりも柔軟です)。

(defn pred [p v] 
   (let [s (read-string (str \# p))] 
      (eval `(apply ~s ~v))))

user=> (map #(pred % [12]) ['(map? %)'(even? %)])
(false true)
于 2012-09-16T08:01:29.540 に答える
3

#(...)リーダーマクロです。リーダーマクロで式を生成できるとは思いません。たとえば、'#(map? %)自動的に(fn* [p1__352#] (map? p1__352#))または同様のものに展開されます。

これは、他のリーダー マクロに関するやや関連性のある議論です。

述語の形式を変更することは可能でしょうか? 次のような場合:

'([arg1] (map? arg1))

次に、関数をそれから作成するのは簡単です。

(cons 'fn '([arg1] (map? arg1)))

(def pred (eval (cons 'fn '([p](map? p)))))
#'predicate.core/pred

(pred {})
true

(pred 10)
false

次に投稿する内容について、私を嫌いにならないでください。関数リーダー マクロの非常に単純化されたバージョンを作成しました。

(defn get-args [p]
  (filter #(.matches (str %) "%\\d*")
          (flatten p)))

(defn gen-args [p]
  (into [] 
        (into (sorted-set) 
              (get-args p))))

(defmacro simulate-reader [p]
  (let [arglist (gen-args p)
        p (if (= (str (first p)) "quote")
            (second p)
            p)]
    (list 'fn (gen-args p) p)))

それを使用するのは非常に簡単です。

((simulate-reader '(map? %)) {}) ; -> true
; or without quote
((simulate-reader (map? %)) {})

; This also works:
((simulate-reader '(+ %1 %2)) 10 5) ; -> 15

@Ankur が提供する他のソリューションとの違いは次のとおりです。

  1. 私は私のものをあまり好きではありません。楽しいことばかりだと思っていました。
  2. 文字列に変換してリーダー マクロを適用する必要はありません。
于 2012-09-16T07:05:14.417 に答える