6

構造化を使用して let 形式に展開するマクロを作成しようとしています。私の問題は、構造化解除によって取得されたものを含め、let 形式で定義されているシンボルのリストが必要なことです。

使用事例

たとえば、検証のために、この種の動作を除外しようとしています:

(let [a (foo bar)
      {x :x,
       y :y,
       {u :u, v: v :as nested-map} :nested} some-map]
  (and x y nested-map u v ; testing truthiness
       (valid-a? a)
       (valid-x? x)
       (valid-y? y)
       (valid-nested? nested-map)
       (valid-u-and-v? u v)
       ))

提案された解決策

次のように呼び出すことができるある種のand-letマクロを使用してこれを実現できれば、非常に便利です。

(and-let [a (foo bar)
          {x :x,
           y :y,
           {u :u, v: v :as nested-map} :nested} some-map]
         (valid-a? a)
         (valid-x? x)
         (valid-nested? nested-map)
         (valid-u-and-v? u v))

私が欠けているもの

しかし、let フォームにバインドされているシンボルのリストにアクセスする方法がありません。関数のようなものがあれば、次のようにするlist-bound-symbolsことができます。

(defmacro and-let
  "Expands to an AND close that previouly checks that the values declared in bindings are truthy, followed by the tests."
  [bindings & tests]
  (let [bound-symbols (list-bound-symbols bindings) ;; what I'm missing
        ]
    `(let ~bindings
       (and 
         ~@bound-symbols
         ~@tests)
     ))) 

誰も私がこれを行う方法の手がかりを持っていますか?

4

2 に答える 2

5

分解はclojure.core/destructure関数によって処理されます。これは公開されているため、自分で呼び出して、すべてのローカルの名前を抽出できます。これには、デストラクチャリングで使用される中間結果の名前を付けるものも含まれます。

(defmacro and-let [bindings & tests]
  (let [destructured (destructure bindings)]
    `(let ~destructured
       (and ~@(take-nth 2 destructured)
            ~@tests))))

うまくいくようです:

(let [foo nil]
  (and-let [a 1
            [b c] [2 3]]
    (nil? foo)))
;= true
于 2014-04-22T10:25:23.933 に答える
0

これのほとんどは、マップを直接処理する関数で行うことができます。

(defn validate [vm ; validation map
                dm ; data map
                ]
  (and
    (every? identity (map #(% dm) (flatten (keys vm))))
    (every? identity (map (fn [[k vf]]
                            (if (vector? k)
                              (apply vf (map #(% dm) k))
                              (vf (k dm))))
                          vm))))

例えば

(validate {:s string?, :n number? :m number? [:m :n] > } {:s "Hello!", :m 5, :n 3})
; true

(validate {:s string?, :n number? :m number? [:m :n] > } {:s "Hello!", :m 5, :n 6})
; false

(validate {:s string?, :n number? :m number? :u \b [:m :n] > } {:s "Hello!", :m 5, :n 6})
; false

aこの例では、不要な変数を事前にマップに追加できます。aこれは、 s の真実性を不必要にテストすることになります。大丈夫です?

于 2014-04-22T11:30:56.467 に答える