步行/步行使用

时间:2012-05-15 05:40:23

标签: clojure

我正在浏览此article on Tree Visitors in Clojure,并看到了以下示例:

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

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

Postwalk的外形是什么?我无法理解它的实用性。邮路如何以及为何使用?任何解释将不胜感激。

2 个答案:

答案 0 :(得分:5)

我不确定你是否在询问#()的含义或做什么(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引用函数的位置参数的参数,其中n表示nth参数,从1开始作为进一步的简写,您可以使用%来引用第一个参数这适用于单个arg匿名函数。这就是你的例子。

所以你的例子相当于

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

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

(walk/postwalk f data)

这里的do是一种特殊形式,来自文档:

  

(做exprs *)   按顺序计算表达式并返回最后一个的值。如果未提供表达式,则返回nil。

事实上defn已经有一个隐含的做法,所以我上面的例子实际上并不需要做...

; 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)

答案 1 :(得分:3)

我今天也有同样的问题,并找到了这个necrotopik。也许以后更新更好。在clojure api reference上找到这个:

  

postwalk   功能   用法:( postwalk f形式)   执行深度优先,后序遍历表单。打电话给   每个子表单,使用f的返回值代替原始值。   识别除sorted-map-by之外的所有Clojure数据结构。   像doall一样消耗seqs。

example from 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或%的原因。向结果添加输入会导致更多嵌套结构。

在上面的示例中,可以看到它遍历嵌套地图结构的深度。首先是地图中最深的元素,然后上升到更高的水平,然后潜伏到下一个形式,然后再次上升并完成整个表单的最后一步。

相关问题