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,因此我将其视为此类问题的官方解决方案,除非该fn的语义不适用于当前情况 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被读取/编译时,并没有执行。要在编译时执行,或许你可以调用一个名为‘function’的宏。

这实际上可行。不过我不理解为什么,你能解释一下吗?
在lambda定义编译成函数时,它已经被执行了0次。因此,在第二行使用之前,还没有进行require操作。(并且我们仍然处于编译状态。)编译器需要知道‘c-set’是什么。
我觉得我理解到那个程度。但是我仍然不明白为什么将require放入宏中可以使得使用`c-set`可行。
唯一的区别是它是在宏展开时执行的。(宏通常是从代码到代码的函数,但在这个例子中,它是用来触发require的操作的副作用。)如果你想要构建包含此类定义的AOT编译库,这可能不是一个解决方案。它在REPL环境中是可行的。

注意:我并不完全理解你的最终用途。
作者:
谢谢。我想我需要稍微思考一下宏展开的时间。=)

我的用例在ClojureScript中(或者更准确地说,在nodejs环境中使用SCI)中,我需要在promise解析后推迟require操作。我还没有在那种解决方案中尝试过,但我将这么做,并报告表现如何。目前我正在使用@Imre的解决方案,这对我来说很好,但我还是想试一下这个。
作者:
对不起,但我的伪宏漏洞在这个情况下不会有用,即使它在REPL中给出了好的结果。Imre是对的。
作者:
实际上在我用例中确实可行。仅供参考。(我将继续使用Imre的解决方案,但无论如何。)
...