(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)
我如何评估此结果列表?
(type (first a))
; => cljs.core/Symbol
(= (first a) '+)
; => true
我更一般地想我如何从符号->函数中得到。 这是Clojure的正常做法吗?我似乎找不到任何东西。也许我搜索的字词不正确。
答案 0 :(得分:5)
您通常会使用eval
。但是在ClojureScript中,您需要在运行时可用的编译器和标准库。仅当您使用自托管的ClojureScript时才有可能。
如果您处于自我托管的环境(例如Lumo,Planck,Replete,Klipse,等),那么eval
就可以正常工作:
cljs.user=> (require '[clojure.edn :as edn])
nil
cljs.user=> (def a (edn/read-string "(+ 1 3)"))
#'cljs.user/a
cljs.user=> (eval a)
4
否则,您可以利用cljs.js
命名空间中的功能来访问自托管的ClojureScript:
cljs.user=> (require 'cljs.js)
nil
cljs.user=> (cljs.js/eval (cljs.js/empty-state)
a {:eval cljs.js/js-eval :context :expr} prn)
{:value 4}
请注意,这样做需要一些大小方面的考虑:ClojureScript编译器将与您编译的工件一起带入目标环境,并且您还必须避免使用
:advanced
,以确保整个cljs.core
标准库并且关联的元数据在运行时可用。
答案 1 :(得分:2)
我的回答似乎仅适用于Clojure,而不适用于ClojureScript。请参见other answer。
我认为您可能正在寻找resolve
。
(defn my-simple-eval [expr]
; Cut the function symbol from the arguments
(let [[f & args] (edn/read-string expr)]
; Resolve f to a function then apply the supplied arguments to it
(apply (resolve f) args)))
(my-simple-eval "(+ 1 3)")
=> 4
参数必须是空数字才能起作用。如果要允许子表达式,可以使其递归:
(defn my-simple-eval-rec [expr]
(letfn [(rec [[f & args]]
(->> args
(map (fn [arg]
(if (list? arg)
(rec arg) ; Process the sub-expr
arg)))
(apply (resolve f))))]
(rec (edn/read-string expr))))
(my-simple-eval-rec "(+ 1 (+ 2 5))")
=> 8
如果这还不够的话,除了使用eval
外,我不知道其他任何方式:
(def a (edn/read-string "(+ 1 3)"))
(eval a)
=> 4
或者,如果扩展宏时数据可用,则只需将调用包装到read-string
即可将数据解释为普通数据:
(defmacro my-read-string [expr]
(edn/read-string expr))
(my-read-string "(+ 1 3)")
=> 4