【问题标题】:Using 'eval' special form in ClojureScript to determine if a form is literal在 ClojureScript 中使用 'eval' 特殊形式来确定一个形式是否是文字
【发布时间】:2016-06-28 22:49:42
【问题描述】:

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

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

这会首先尝试评估表单;如果失败,那么我们将表单视为文字。

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

该函数在 .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)

有人有可以在 ClojureScript 中使用的解决方案吗?

提前致谢!

【问题讨论】:

    标签: javascript clojure clojurescript


    【解决方案1】:

    有可能,但有点棘手!

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

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

    然后检查你的开发者控制台,你会看到:

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

    以及发生的其他输出。

    希望这能让您相信 (a) eval 有效! (b) cljs 中的 eval 稍微复杂一些。

    为什么您可能会问所有的 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)))
    

    并且产生同样的效果:

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

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

    这里有一些参考资料,因为......这很令人困惑,这些提供了很好的细节:

    1. http://clojurescript.io/查看构建此站点的代码。
    2. 阅读 Mike Fikes 博客! https://blog.fikesfarm.com/posts/2016-01-22-clojurescript-eval.html(和其他帖子)他编写了大部分引导代码并在普朗克积极使用它。
    3. https://yogthos.net/posts/2015-11-12-ClojureScript-Eval.html
    4. http://ctford.github.io/klangmeister/ 很好的预加载状态参考。

    【讨论】:

    • 感谢您提供详细信息;当我尝试在我的命名空间中要求 cljs.js 时,我得到一个“goog.require 找不到:cljs.js”。我需要将依赖项添加到我的 project.clj 吗?如果这很明显,我们深表歉意!
    • 很可能是ClojureScript版本的问题,cljs.js是最近才添加的。作为参考,我尝试使用 1.8.51(但现在有更新的版本)。如果使用更新的版本可以为您解决问题,请告诉我。
    • 我将我的 Clojure、ClojureScript 和 lein 版本分别更新为 1.8.0、1.9.89 和 1.1.3,在修复了其他一些漏洞之后,一切似乎都正常了;干杯!
    • 您的意思是链接到 Mike Fikes 的此博客条目吗? blog.fikesfarm.com/posts/2016-01-22-clojurescript-eval.html
    • 很好,这似乎更相关;我已经编辑包括在内。
    猜你喜欢
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 2019-12-24
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    相关资源
    最近更新 更多