我有一個結構,其中第一個元素是一個函數,其餘的參數指向fn。現在每個arg可以反過來是一個具有類似charectristic的向量。如何寫一個遞歸fn來評估下面的結構
[+ 1 2 3 [- 4 3] 5 6 [- 9 8 [+ 5 6]] 4 5]
我如何寫一個遞歸FN給出任何這樣的向量計算出結果?還有什麼方法來評估它,因爲如果向量可以用()替換,結構將是一個有效的clojure形式?
我有一個結構,其中第一個元素是一個函數,其餘的參數指向fn。現在每個arg可以反過來是一個具有類似charectristic的向量。如何寫一個遞歸fn來評估下面的結構
[+ 1 2 3 [- 4 3] 5 6 [- 9 8 [+ 5 6]] 4 5]
我如何寫一個遞歸FN給出任何這樣的向量計算出結果?還有什麼方法來評估它,因爲如果向量可以用()替換,結構將是一個有效的clojure形式?
user=> (def d '[+ 1 2 3 [- 4 3] 5 6 [- 9 8 [+ 5 6]] 4 5])
#'user/d
user=> (defn to-list [elt]
#_=> (if (vector? elt) (map to-list elt) elt))
user=> (to-list d)
(+ 1 2 3 (- 4 3) 5 6 (- 9 8 (+ 5 6)) 4 5)
user=> (eval *1)
17
值得一提的是,eval
將這裏的時間相當顯著量:
;; to-list as in Michiel's answer, v is the example from the question
user=> (time (dotimes [_ 100] (eval (to-list v))))
"Elapsed time: 192.098235 msecs"
一個簡單的自定義功能,可以比一個數量級更快更多:
user=> (defn calcvec [v]
(if (vector? v)
(apply (resolve (first v))
(map calcvec (next v)))
v))
#'user/calcvec
user=> (calcvec v)
17
user=> (time (dotimes [_ 100] (calcvec v)))
"Elapsed time: 15.87096 msecs"
我試圖用Criterium作爲基準,但quick-bench
需要方式太長了eval
版本所以我最終殺了它。 (雖然它與calcvec
沒有關係)。
一般而言,eval
對於很少執行操作(可能只有一次)的操作是最有意義的,比如從一個動態構建的代碼塊編譯一個函數等等。所以,如果你只需要計算一些這樣的向量的值,eval
方法是好的;否則你會更好用calcvec
或類似的東西。毫無疑問,eval
版本可以做得更多,例如它可以處理特殊的表單和宏。