1

我有一个结构,其中第一个元素是函数,其余的 args 到 fn。现在每个 arg 又可以是具有相似特征的向量。

[+ 1 2 3 [- 4 3] 5 6 [- 9 8 [+ 5 6]] 4 5]

如何编写递归 fn 来计算给定任何此类向量的结果?还有什么方法可以评估它,因为如果向量可以用 () 替换,结构将是有效的 clojure 形式?

4

2 回答 2

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
于 2013-04-23T17:57:21.567 回答
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版本可以做更多的事情,例如它可以处理特殊的表格和宏。

于 2013-04-24T22:45:39.360 回答