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

欢迎!请查看关于页面,了解有关如何工作的更多信息。

+1
编译器 by

为什么我不能像这样在函数中使用 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
by
选择 by
 
最佳答案

为什么不直接使用 requiring-resolve?

编辑,以获取更多详细信息

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

根据与 Peter(论坛)在线交谈得知,该代码无法正常工作的原因是它名为 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中它可行。

注意:我不太明白你的最终用途。
by
谢谢。我觉得我需要思考一下宏展开的时刻。=)

我的用例是在 ClojureScript 中(或者更确切地说,在 nodejs 环境中的 SCI 中) ,我需要将 require 延迟到 promise 解决。我还没有在那里尝试这个解决方案,但我会试试看效果如何。现在我在使用 @Imre 的解决方案,这对于我的用例来说很不错,但我还是想试用一下这个方案。
by
抱歉,但我的伪宏破解在这个用例中不太适用,尽管它在 REPL 中给出了很好的结果。Imre 是对的。
by
实际上对于我的用例它是有效的。顺便说一下。(我将继续使用 Imre 的解决方案,但无论如何。)
...