如何评估edn /阅读清单?

时间:2019-05-04 22:22:29

标签: clojure eval clojurescript edn

(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)

我如何评估此结果列表?

(type (first a))
; => cljs.core/Symbol

(= (first a) '+)
; => true

我更一般地想我如何从符号->函数中得到。 这是Clojure的正常做法吗?我似乎找不到任何东西。也许我搜索的字词不正确。

2 个答案:

答案 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