请在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中(或者更准确地说是SCI在nodejs环境中),我需要在promise解析后推迟一个require。我还没有在那里尝试这个解决方案,但我将那样做并报告我的结果。现在,我正在使用@Imre的解决方案,对于我的用途来说这很好,但我仍然想尝试一下这个方案。
抱歉,但我的伪宏在这个情况下将不起作用,即使它在REPL中给出了好的结果。Imre是对的。
实际上在我的情况下它确实有效。公示。(我会坚持使用Imre的解决方案,但无论如何。)
...