Как мне оценить список edn / read? - PullRequest
0 голосов
/ 05 мая 2019
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)

Как мне оценить этот результирующий список?

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

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

Я полагаю, в более общем смысле, как бы я получил от символа -> функции.И это нормальная практика в clojure?Я не могу найти что-либо на этом.Возможно, я не ищу правильные термины.

Ответы [ 2 ]

5 голосов
/ 06 мая 2019

Обычно вы используете 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 голосов
/ 05 мая 2019

Кажется, мой ответ работает только в 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
...