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,因此,除非该函数的语义不适合当前情况,我将它视为这类问题的官方解决方案 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被读取/编译时,它并没有被执行。要在编译时执行,也许你可以调用一个宏的'函数'。

这实际上管用。为什么我不太明白。你能解释一下吗?
当lambda定义作为函数编译时,它已经被执行了0次。因此,在第二行它被使用之前,还没有执行require。(我们仍然处于编译时。)编译器需要知道什么是'c-set'。
我认为我已经理解到那里。但我不明白为什么将require wraps in a macro会使c-set的使用变得有效。
唯一的区别在于它是在宏展开时执行的。(宏通常是从代码到代码的函数,但在这个情况下,它是用来调用require的副作用。)如果你想要构建一个使用这些定义的AOT编译库,这可能不是你问题的解决方案。但它在REPL中是工作的。

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

我的用例是在ClojureScript(或者在nodejs环境中,应该说SCI)中,我需要在promise解析后再进行require。我还没有在那儿尝试这个解决方案,但我会去做并且汇报结果。现在我在用@Imre的解决方案,它在我的用例中很好用,但我还是想试试这个。
by
抱歉,即使我的伪宏在REPL中给出了好结果,但在这个情况下它依然没有用,Imre是对的。
by
实际上,在我的用例中它是有效的。仅供参考。(我会坚持用Imre的解决方案,但无论如何。)
...