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中的这里这里

是的,为什么不呢?你能详细说明一下吗?
(评论
      ;(->> [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被读取/编译时,它并没有被执行。要实现在编译时执行,或许可以调用一个'macro'函数。

这实际上是可以工作的。但我不太理解为什么会这样。你能解释一下吗?
当lambda定义被编译为函数时,它已经执行了0次。因此,要求在没有执行的情况下已经使用了这种定义。(我们仍然处于编译时。编译器需要知道'c-set'是什么。)
我似乎理解了前面的东西,但我不太理解为什么在宏中将require进行包装会产生使`c-set`使用工作。
唯一的区别是它是在宏展开时执行的。(宏通常是从代码到代码的函数,但在这个例子中,它是用来调用require的副作用。)如果你想要构建带有这些定义的AOT编译库,这可能不是你的解决方案。在REPL中它是工作的。

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

我的适用场景在ClojureScript中(或者说在nodejs环境中更准确一点是SCI)需要将require延迟到promise解析完成。我还没有尝试这个解决方案,但我会尝试并回报结果。现在,我正在使用@Imre的办法,它对我的用例来说已经足够好了,但我还是想试试这个方案。
by
抱歉,我的伪宏的修改在这个场景下将不会有用,尽管它在REPL中有好结果。Imre是对的。
by
实际上,它在我的用例中确实起作用了。顺便说一下。(我会坚持使用Imre的方案,但无论如何。)
...