4

Clojure のツリー ビジターに関するこの記事を読んでいて、以下の例に出くわしました。

(def data [[1 :foo] [2 [3 [4 "abc"]] 5]])

(walk/postwalk #(do (println "visiting:" %) %) data)

ポストウォークの外形は何をしているの?その有用性が理解できません。postwalk はどのように、そしてなぜ使用されるのですか? 説明をいただければ幸いです。

4

2 に答える 2

7

#()が何を意味するのか、do(form1 form2)の目的が何を意味するのかわからないので、両方に答えます。

#()匿名関数を宣言するための省略形です。匿名関数は、ある関数を別の関数に渡すときに役立ちます。

説明のために、これをreplで見てください

; define an anonymous function
user=> #(+ %1 %2)
#<user$eval68$fn__69 user$eval68$fn__69@9fe84e>

; is equivalent to 
user => (fn [a b] (+ a b))
#<user$eval1951$fn__1952 user$eval1951$fn__1952@118bd3c>

; furthermore, you could then assign your anonymous function to a var
(def f #(+ %1 %2))

; is equivalent to 
(defn f [a b] (+ a b))

user=> (#(+ %1 %2) 1 2)
3

user=> (f 1 2)
3

%n、関数の位置引数への引数を参照します。ここで、は1から始まる引数をn意味nthします。さらに簡略化すると、%を使用して、単一引数の無名関数で適切に機能する最初の引数を参照できます。これはあなたの例にあるものです。

したがって、例は次のようになります

(def data [[1 :foo] [2 [3 [4 "abc"]] 5]])

(defn f [x] (do (println "visiting:" x) x))

(walk/postwalk f data)

ここdoに特別なフォームがあります。これはドキュメントからのものです。

(do exprs *)式を順番に評価し、最後の値を返します。式が指定されていない場合は、nilを返します。

実際defn、すでに暗黙のdoがあるので、上記の例では実際にはdoを必要としません...

; your example is equivalent to:

(def data [[1 :foo] [2 [3 [4 "abc"]] 5]])

(defn f [x] (println "visiting:" x) x)

(walk/postwalk f data)
于 2012-05-15T08:52:34.110 に答える
5

今日も同じ質問があり、このネクロトピックを見つけました。遅い方が新しいのかもしれません。clojure APIリファレンスでこれを見つけてください:

postwalk 関数 使用法: (postwalk f form) form の深さ優先の後順トラバーサルを実行します。各サブフォームで f を呼び出し、元の代わりに f の戻り値を使用します。sorted-map-by を除くすべての Clojure データ構造を認識します。doall と同様に seq を消費します。

また、このclojuredocs の例は物事をより明確にします:

(use 'clojure.walk)
(let [counter (atom -1)]
(postwalk (fn [x]
            [(swap! counter inc) x])
              {:a 1 :b 2}))

  => [6 {2 [[0 :a] [1 1]], 5 [[3 :b] [4 2]]}] 

したがって、postwalk はすべてのサブフォームを関数の結果に置き換えます。ネストされた構造を新しい値で更新するために使用されます。そのため、結果の関数の末尾に x または % が含まれます。結果に入力を追加すると、さらにネストされた構造になります。

上の例では、ネストされたマップ構造の深さを通り抜ける様子が見られます。最初にマップの最も深い要素に移動し、次に高いレベルに移動し、次のフォームに潜伏し、再び上昇してフォーム全体で最後の移動を終了します。

于 2013-06-02T01:59:12.490 に答える