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 (作者) 线下交谈中学到的,这段特定的代码为什么不起作用的原因被命名为 Gilardi 场景。问题的扩展描述可以在 ClojureDocs 中找到。

当可能使用 requiring-resolve 时,另一个原因是 Clojure 1.11.1 中 require 不是线程安全的。更多细节可以在这个问题中找到,并且在 ClojureDocs 的这里这里

by
是的,为什么不呢?你能详细说明一下吗?
by
(评论
      (->> [1 2]
           (reduce (fn [acc v]
                     ((requiring-resolve 'clojure.set/union) acc #{v}))
             #{}))
      ;;=> #{1 2}
      )
by
reshown by
一点补充:tools.build大量使用requiring-resolve,因此我认为这是此类问题的官方解决方案,除非该fn的语义不适合当前情况 https://github.com/clojure/tools.build/blob/a9d0804ce8014088a7388e762034e9013922cacb/src/main/clojure/clojure/tools/build/api.clj#L126
+1
by
编辑 by

我尝试了这个

(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读取/编译时,并没有执行。要实现在编译时执行,或许你可以调用一个'macro function'。

by
这实际上生效了。但我不知道为什么,你能解释一下吗?
by
当lambda定义被编译成函数时,它已经执行了0次。因此,在第二行它已经使用时,require还没有进行。 (我们仍然处于编译时。) 编译器需要知道'c-set'是什么。
by
我觉得我理解到这里,但我不明白为什么把require包装在macro里面使得`c-set`的使用生效。
by
唯一的不同之处在于它是在宏扩展时执行的。(宏通常是从代码到代码的函数,但在此情况下,它用于调用require的副作用。)如果您想构建带有此类定义的AOT编译库,这可能不是您的解决方案。它在REPL上可以工作。

注意:我不太理解您的最终用途。
by
谢谢。我想我需要稍微想一下宏何时展开。=)

我的用例是在ClojureScript中(或者更确切地说在nodejs环境中使用SCI) 其中我需要将require推迟到promise解决之后。我还没有尝试这个解决方案,但我会尝试一下,并回来报告我的结果。现在,我正在使用@Imre的解决方案,这对我来说很好,但我仍然想尝试这个方案。
by
抱歉,但我的伪宏 hacking 在这个情况下将没有任何用,尽管它在REPL中给出了好的结果。Imre是对的。
by
实际上,它在我的用例中确实有效。仅供参考。(我会坚持使用Imre的解决方案,但无论如何。)
...