我正在阅读关于Clojure中的Tree Visitors的这篇文章,并且遇到了以下示例:
(def data [[1 :foo] [2 [3 [4 "abc"]] 5]])
(walk/postwalk #(do (println "visiting:" %) %) data)
Run Code Online (Sandbox Code Playgroud)
邮政行走的外形是什么?我无法理解它的实用性.邮路如何以及为何使用?任何解释将不胜感激.
我不确定你是否在询问#()的含义或做什么(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
Run Code Online (Sandbox Code Playgroud)
所述%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)
Run Code Online (Sandbox Code Playgroud)
这do是一个特殊的表格,来自文档:
(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)
Run Code Online (Sandbox Code Playgroud)
我今天有同样的问题,并找到了这个 necrotopik。也许越晚越好。在clojure api 参考中找到这个:
postwalk 函数用法:(postwalk f form) 执行表单的深度优先、后序遍历。在每个子表单上调用 f,使用 f 的返回值代替原始值。识别除 sorted-map-by 之外的所有 Clojure 数据结构。与 doall 一样消耗 seqs。
来自 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]]}]
Run Code Online (Sandbox Code Playgroud)
所以,postwalk 用函数的结果替换每个子表单。它用于使用新值更新嵌套结构。这就是结果函数最后包含 x 或 % 的原因。向结果添加输入会导致更多的嵌套结构。
在上面的示例中,可以看到它穿过嵌套地图结构的深度。它首先在地图的最深元素上移动,然后上升到更高级别,然后潜伏到下一个形式,然后再次上升并完成整个形式的最后一步。