2024 Clojure状态调查!分享你的想法。

欢迎!请参阅关于页面,以了解更多关于该功能的信息。

+1 投票
编译器

为什么我不能像这样在函数中使用require?

(comment
  (->> [1 2]
       (reduce (fn [acc v]
                 (require '[clojure.set :as c-set])
                 (c-set/union acc #{v}))
               #{})) ;=> Syntax error compiling at (lab/sandbox_playground.clj:31:18).
                     ;   No such namespace: c-set
  )

最初我以为是要将require放在顶层。然而:这工作正常

(comment
  (do
    (require '[clojure.set :as c-set])
    (c-set/union #{1} #{2})) ;=> #{1 2}
  )

2 答案

+3 投票

选定
 
最佳答案

为什么不用requiring-resolve?

编辑,了解更多细节

(comment
  (->> [1 2]
       (reduce (fn [acc v]
                 ((requiring-resolve 'clojure.set/union) acc #{v}))
         #{}))
  ;;=> #{1 2}
  )

正如我在与Peter(op)进行线下交谈时学到的,特定代码不能工作的原因是Gilardi场景。关于该问题的详细描述可在ClojureDocs中找到。

当可能时,另一个更喜欢使用requiring-resolve的原因是,从Clojure 1.11.1开始,require不是线程安全的。关于此的更多详情可在(其他地方)此问题中找到,以及ClojureDocs的这里这里

是的,为什么不呢?你能详细说明一下吗?
(评论
      (->> [1 2]
           (reduce (fn [acc v]
                     ((requiring-resolve 'clojure.set/union) acc #{v}))
             #{}))
      ;;=> #{1 2}
      )

再次评论
一点补充:tools.build 严重依赖于requiring-resolve,因此我认为它是处理此类问题的官方解决方案,除非该函数的语义不适合当前案例 https://github.com/clojure/tools.build/blob/a9d0804ce8014088a7388e762034e9013922cacb/src/main/clojure/clojure/tools/build/api.clj#L126
+1 投票

编辑

我试了这种方法

(defmacro require-macro [arg]
  (require arg))

(->> [1 2]
 (reduce (fn [acc v]
           (require-macro [clojure.set :as c-set])
           (c-set/union acc #{v}))
         #{}))

我认为当lambda读取/编译时,它并未执行。要实现在编译时执行,也许你可以调用一个宏'函数'。

这确实有效。但我仍然不明白原因。你能解释一下吗?
当lambda定义作为函数编译时,它被执行了0次。因此,当在第二行使用时,尚未进行require操作。(我们仍然处于编译时。)编译器需要知道'c-set'是什么。
我认为我已经理解到了这里。但我仍然不明白为什么将require包裹在宏中可以使`c-set`的用法正常。
唯一的不同之处在于它是在宏展开时执行的。(宏通常是从代码到代码的函数,但在这个案例中,它被用于触发require的副作用。)如果想要建立包含此类定义的AOT(增量)编译库,这可能不是解决方案。然而它在REPL(即时编程环境)中是有效的。

注意:我对您的最终用途不太理解。
谢谢。我想我得稍微想想宏展开的问题。=)

我的场景是ClojureScript(或更确切地说是在Nodejs环境中运行SCI),我需要在promise解析后推迟require。我还没有在那里尝试这个解决方案,但我会这么做并报告效果。现在我在使用Imre的解决方案,这对我的场景来说是足够的,但我仍然想尝试一下这个解决方案。
抱歉,但我的这个伪宏的Hack方法在这个场景中可能没用,尽管它在REPL中给出了好的结果。Imre是对的。
实际上在我的场景中它确实可以工作。仅供了解。(我将继续使用Imre的解决方案,但无论如何。)
...