我有一个结构,其中第一个元素是一个函数,其余的元素是fn。现在每个arg可以反过来成为具有类似charectristic的向量。
[+ 1 2 3 [- 4 3] 5 6 [- 9 8 [+ 5 6]] 4 5]
如何在给定任何此类向量的情况下编写递归fn来计算结果?还有什么方法可以评估它,因为如果向量可以被()替换,结构将是一个有效的clojure形式?
答案 0 :(得分:5)
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
答案 1 :(得分:1)
值得注意的是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
版本可以做得更多,例如它将处理特殊形式和宏。