私が理解しているように、walk と map はどちらも関数を seq に適用します。(walk では、outer
関数の後処理を適用することもできます)。しかし、一方を他方の上に使用する慣用的なケースは何ですか?
3 に答える
のセマンティクスmap
は基本的に次のとおりです。コレクション内の各アイテムに関数を適用し、結果を遅延してシーケンスで返します。
(map inc #{0 1 2}) ;outputs (when realized) (1 2 3)
入力はセットですが、出力はシーケンスであることに注意してください。
walk のセマンティクスは基本的に次のとおりです。各項目がその項目の関数の値に置き換えられた同じ型のコレクションを作成し、新しいコレクションinner
に適用した結果を返します。outer
(walk inc identity #{0 1 2}) ;outputs #{1 2 3}
walk API の他の関数のソース コード ( http://richhickey.github.com/clojure/clojure.walk-api.html ) を見ると、walk を再帰的にする方法もわかります (またはそれらの他の機能を使用してください)。
イディオムに関する限り、私にはわかりません。しかしwalk
、より複雑なので、提供map
されるセマンティクスが必要ない場合は、おそらく固執する必要がありwalk
ます。
関数を seq に適用するのは map の仕事です。構造全体を再帰的にトラバースする必要がある場合は、 walk を使用します。
walk
s のいくつかの例はClojureDocs にあります。REPLにもあります(user/clojuredocs clojure.walk/postwalk)
。例の多くは教育的であり、実際にはmap
またはfor
(場合によってreduce
は ) を使用して実行できますし、実行する必要があります。
a の典型的な使用例は、walk
再帰的に処理したいネストされた構造がある場合です。これが役立つ可能性があるいくつかの例は、clojure.walk
名前空間自体です。たとえば、 を見てください(source clojure.walk/keywordize-keys)
。[注: 反復的に、または自由に処理したい場合は、zipper を使用してください (またはtree-seq
、より単純な反復処理の場合)。
頭に浮かぶ別の例は、解析ツリーの解釈です。
(require '[clojure.walk :as w])
(def t [+ [* [- 6 2] [/ 9 3]] [* 2 [+ 7 8]]])
(w/postwalk #(if (and (coll? %) (fn? (first %))) (apply (first %) (next %)) %) t)
;=> 42
あまりにも強力な eval コンパイラを呼び出す代わりに、 などに置き換えfn?
てednallowed-fn?
式を評価する場合などに、おそらく便利です。
(eval t) ;=> [#<core$_PLUS_ ... ]
おっと、フォームはベクトルではなくリストです:
(def s (w/postwalk #(if (coll? %) (apply list %) %) t))
s ;=> (#<core$_PLUS_ ... )
(eval s) ;=> 42
ああ、ここで a の別の使用法に注意してくださいwalk
-- ネストされたベクトルからネストされたリストに構造を再帰的に変更します。
熟考するための反復例:
(require '[clojure.walk :as w])
(def s1 (range 8))
s1 ;=> (0 1 2 3 4 5 6 7)
(map inc s1)
;=> (1 2 3 4 5 6 7 8)
(w/postwalk #(if (number? %) (inc %) %) s1)
;=> (1 2 3 4 5 6 7 8)
(def s2 (partition 2 s1))
s2 ;=> ((0 1) (2 3) (4 5) (6 7))
(map (partial map inc) s2)
;=> ((1 2) (3 4) (5 6) (7 8))
(w/postwalk #(if (number? %) (inc %) %) s2)
;=> ((1 2) (3 4) (5 6) (7 8))
(def s3 (partition 2 s2))
s3 ;=> ((0 1) (2 3) (4 5) (6 7))
(map (partial map (partial map inc)) s3)
;=> (((1 2) (3 4)) ((5 6) (7 8)))
(w/postwalk #(if (number? %) (inc %) %) s3)
;=> (((1 2) (3 4)) ((5 6) (7 8)))
(def s4 (partition 2 s3))
s4 ;=> ((((0 1) (2 3)) ((4 5) (6 7))))
(map (partial map (partial map (partial map inc))) s4)
;=> ((((1 2) (3 4)) ((5 6) (7 8))))
(w/postwalk #(if (number? %) (inc %) %) s4)
;=> ((((1 2) (3 4)) ((5 6) (7 8))))