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

欢迎!请参见关于页面,了解更多关于此功能的信息。

+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}
      )

reshown
另外一点需要注意的是,tools.build大量使用了requiring-resolve,因此我认为在语义不适用于当前情况之前,它作为此类问题的官方解决方案。 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次。因此,在第二行就已经使用时,require还没有被执行。(我们仍然处于编译时。)编译器需要知道'c-set'是什么。
我认为我理解了那里的情况。但我不明白为什么将require包裹在宏中可以使得使用`c-set`正常工作。
只有一点不同,它是宏展开时执行的。(宏通常是代码到代码的函数,但在这个例子中,它用于调用require的副作用。)如果你想要使用这种定义构建AOT编译的库,这 probably不是你的问题的解决方案。在REPL中它却可行。

注意:我不太明白你的最终用法。
谢谢。我猜我需要考虑一下宏展开的时候。=)

我的用例是在ClojureScript中(或者说在nodejs环境中使用SCI),我需要在promise解析之后再进行require。我还未在此解决方案中尝试,但我将尝试并报告我的进展。目前,我正在使用@Imre的解决方案,这对我的用例来说已经足够好了,但我想还是会尝试一下这个方案。
by
抱歉,但我使用伪宏的技巧在这种情况下将没有用处,尽管在REPL中结果显示良好。Imre是对的。
by
实际上,在我的用例中它是可行的。仅供参考。(我会坚持使用Imre的解决方案,但无论如何。)
...