在ClojureScript中使用“eval”特殊表单来确定表单是否为文字

时间:2022-11-23 09:26:19

I'm writing a function which determines if a form (e.g (reverse [1 2 3])) is literal. To do this I have the following code:

我正在编写一个函数来确定一个表单(例如(反向[1 2 3]))是否是字面的。为此,我有以下代码:

(defn literal? [form]
(let [evaluation (try
                     (eval form)
                     (catch Exception exception false))]
    (if evaluation
      (= evaluation form)
      true)))

This tries to evaluate the form first; if that fails then we consider the form as literal.

这会先尝试评估表单;如果失败,那么我们认为表格是字面的。

If the form evaluates successfully then we check further if the evaluation is equal to the form itself. If so it is literal.

如果表单成功评估,那么我们进一步检查评估是否等于表单本身。如果是这样,那就是文字。

The function works when applied to [1 2 3] in a .clj file, but in a .cljs file I get the following error:

该函数在.clj文件中应用于[1 2 3]时有效,但在.cljs文件中,我收到以下错误:

TypeError: Cannot read property 'call' of undefined
    at eval (/home/peter/ide/src-cljs/ide/core.cljs[eval16]:71:14)
    at eval (native)
    at Function.<anonymous> (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:35236:461)
    at b (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:6188:14)
    at a (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:6234:18)
    at cljs.core.do_dispatch (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:13583:26)
    at cljs.core.MultiFn.cljs$core$IMultiFn$_dispatch$arity$2 (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:13655:32)
    at cljs.core._dispatch (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:13568:14)
    at a (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:13662:32)
    at b [as call] (file:///opt/lighttable-0.8.1-linux/resources/app/core/node_modules/lighttable/bootstrap.js:13666:14)

Does anyone have a solution which will work in ClojureScript?

有没有人有一个可以在ClojureScript中使用的解决方案?

Thanks in advance!

提前致谢!

1 个解决方案

#1


4  

It is possible, but it's a little tricky!

这是可能的,但它有点棘手!

If you go to clojurescript.io and enter this mysterious incantation:

如果你去clojurescript.io并输入这个神秘的咒语:

(js/cljs.js.eval (js/cljs.js.empty-state) [1 2 3] (fn [x] (prn "********" x)))

Then check your developer console, you will see:

然后检查您的开发者控制台,您将看到:

"********" {:value [1 2 3]}

Along with other output that occurs.

与其他输出一起发生。

Hopefully this convinces you that (a) eval works! (b) eval is a little more complicated in cljs.

希望这能说服你(a)eval有效! (b)eval在cljs中稍微复杂一些。

Why all the js interop you may ask? Well in the context of the REPL that is executing, those symbols aren't in the current state of the compiler, as the javascript was created when the site was compiled. There are ways to preload the state, but require some work to achieve. Don't worry, none of that is relevant if you are calling eval as part of your program (instead of from the REPL). If you are using eval in your program you can write code like this:

为什么所有的js互操作你可能会问?在正在执行的REPL的上下文中,这些符号不在编译器的当前状态,因为javascript是在编译站点时创建的。有预加载状态的方法,但需要一些工作来实现。不要担心,如果您将eval作为程序的一部分(而不是来自REPL),那么这些都不相关。如果您在程序中使用eval,则可以编写如下代码:

(ns ....... (:require .....
  [cljs.js :refer [eval empty-state js-eval]]))


(eval (empty-state)
        [1 2 3]
        {:eval       js-eval
         :source-map true
         :context    :expr}
        (fn [x] (prn "*****" x)))

And it produces the same effect:

它产生同样的效果:

"*****" {:value [1 2 3]}

In short, you need to refer eval from cljs.js, and it requires some state to be passed along.

简而言之,您需要从cljs.js引用eval,它需要传递一些状态。

Here are some references, because... it's confusing, and these give great details:

以下是一些参考资料,因为......这令人困惑,这些都给出了很多细节:

  1. http://clojurescript.io/ Check out the code for building this site.
  2. http://clojurescript.io/查看构建此站点的代码。
  3. Read Mike Fikes blog! http://blog.fikesfarm.com/posts/2016-01-05-clojurescript-macros-calling-functions.html He wrote most of the bootstrapping code and uses it actively in Planck.
  4. 阅读Mike Fikes博客! http://blog.fikesfarm.com/posts/2016-01-05-clojurescript-macros-calling-functions.html他编写了大部分引导代码并在普朗克中主动使用它。
  5. https://yogthos.net/posts/2015-11-12-ClojureScript-Eval.html
  6. https://yogthos.net/posts/2015-11-12-ClojureScript-Eval.html
  7. http://ctford.github.io/klangmeister/ Great reference for preloading state.
  8. http://ctford.github.io/klangmeister/预加载状态的很好的参考。

#1


4  

It is possible, but it's a little tricky!

这是可能的,但它有点棘手!

If you go to clojurescript.io and enter this mysterious incantation:

如果你去clojurescript.io并输入这个神秘的咒语:

(js/cljs.js.eval (js/cljs.js.empty-state) [1 2 3] (fn [x] (prn "********" x)))

Then check your developer console, you will see:

然后检查您的开发者控制台,您将看到:

"********" {:value [1 2 3]}

Along with other output that occurs.

与其他输出一起发生。

Hopefully this convinces you that (a) eval works! (b) eval is a little more complicated in cljs.

希望这能说服你(a)eval有效! (b)eval在cljs中稍微复杂一些。

Why all the js interop you may ask? Well in the context of the REPL that is executing, those symbols aren't in the current state of the compiler, as the javascript was created when the site was compiled. There are ways to preload the state, but require some work to achieve. Don't worry, none of that is relevant if you are calling eval as part of your program (instead of from the REPL). If you are using eval in your program you can write code like this:

为什么所有的js互操作你可能会问?在正在执行的REPL的上下文中,这些符号不在编译器的当前状态,因为javascript是在编译站点时创建的。有预加载状态的方法,但需要一些工作来实现。不要担心,如果您将eval作为程序的一部分(而不是来自REPL),那么这些都不相关。如果您在程序中使用eval,则可以编写如下代码:

(ns ....... (:require .....
  [cljs.js :refer [eval empty-state js-eval]]))


(eval (empty-state)
        [1 2 3]
        {:eval       js-eval
         :source-map true
         :context    :expr}
        (fn [x] (prn "*****" x)))

And it produces the same effect:

它产生同样的效果:

"*****" {:value [1 2 3]}

In short, you need to refer eval from cljs.js, and it requires some state to be passed along.

简而言之,您需要从cljs.js引用eval,它需要传递一些状态。

Here are some references, because... it's confusing, and these give great details:

以下是一些参考资料,因为......这令人困惑,这些都给出了很多细节:

  1. http://clojurescript.io/ Check out the code for building this site.
  2. http://clojurescript.io/查看构建此站点的代码。
  3. Read Mike Fikes blog! http://blog.fikesfarm.com/posts/2016-01-05-clojurescript-macros-calling-functions.html He wrote most of the bootstrapping code and uses it actively in Planck.
  4. 阅读Mike Fikes博客! http://blog.fikesfarm.com/posts/2016-01-05-clojurescript-macros-calling-functions.html他编写了大部分引导代码并在普朗克中主动使用它。
  5. https://yogthos.net/posts/2015-11-12-ClojureScript-Eval.html
  6. https://yogthos.net/posts/2015-11-12-ClojureScript-Eval.html
  7. http://ctford.github.io/klangmeister/ Great reference for preloading state.
  8. http://ctford.github.io/klangmeister/预加载状态的很好的参考。