【问题标题】:How do I evaluate an edn/read list?如何评估 edn/阅读列表?
【发布时间】:2019-05-06 22:26:45
【问题描述】:
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)

如何评估这个结果列表?

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

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

我想更一般地说,我将如何从符号 -> 函数中获得。 这是clojure的正常做法吗?我似乎找不到任何东西。也许我没有使用正确的术语进行搜索。

【问题讨论】:

    标签: clojure eval clojurescript edn


    【解决方案1】:

    您通常会使用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 标准库和相关元数据是在运行时可用。

    【讨论】:

      【解决方案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
      

      【讨论】:

      • 啊,好的,感谢您的回答。所以看起来我一直在使用 cljs repl。这些在正常的复制中工作。这是我在 cljs 中对符号使用 resolve 时得到的结果:clojure.lang.ExceptionInfo : java.lang.AssertionError : Assert failed: Argument to resolve must be aquoted symbol (core/and (seq?quoted-sym) (= (quote quote) (firstquoted-sym)))
      • @koboldsinparis 老实说,我不知道 ClojureScript。早上我可以试试看。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多