我有一个结构,其中第一个元素是函数,其余的 args 到 fn。现在每个 arg 又可以是具有相似特征的向量。
[+ 1 2 3 [- 4 3] 5 6 [- 9 8 [+ 5 6]] 4 5]
如何编写递归 fn 来计算给定任何此类向量的结果?还有什么方法可以评估它,因为如果向量可以用 () 替换,结构将是有效的 clojure 形式?
我有一个结构,其中第一个元素是函数,其余的 args 到 fn。现在每个 arg 又可以是具有相似特征的向量。
[+ 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
版本可以做更多的事情,例如它可以处理特殊的表格和宏。