如何评估 edn/read 列表?
How do I evaluate an edn/read list?
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)
如何评估此结果列表?
(type (first a))
; => cljs.core/Symbol
(= (first a) '+)
; => true
我想更一般地说,我将如何从符号 -> 函数中获得。
这是 clojure 中的正常做法吗?我似乎在上面找不到任何东西。可能我没有使用正确的术语进行搜索。
我的回答似乎只适用于 Clojure,不适用于 ClojureScript。参见。
我想您可能正在寻找 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
您通常会使用 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}
Note that doing this carries some size considerations: The ClojureScript compiler will be brought with your compiled artifacts into the target environment, and you must also avoid using :advanced
, ensuring that the entire cljs.core
standard lib and associated metadata is available at runtime.
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)
如何评估此结果列表?
(type (first a))
; => cljs.core/Symbol
(= (first a) '+)
; => true
我想更一般地说,我将如何从符号 -> 函数中获得。 这是 clojure 中的正常做法吗?我似乎在上面找不到任何东西。可能我没有使用正确的术语进行搜索。
我的回答似乎只适用于 Clojure,不适用于 ClojureScript。参见
我想您可能正在寻找 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
您通常会使用 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}
Note that doing this carries some size considerations: The ClojureScript compiler will be brought with your compiled artifacts into the target environment, and you must also avoid using
:advanced
, ensuring that the entirecljs.core
standard lib and associated metadata is available at runtime.