请在 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不是线程安全的。关于这一点的更多详情可以在这个问答以及其他(如这里这里)找到。

是的,为什么不呢?你能详细说明一下吗?
(comment
       (->> [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时,它并没有被执行。为了在编译时执行,也许你可以调用一个'function'宏。

这实际上有效。尽管如此,我也不明白原因。你能解释一下吗?
当lambda的声明被编译为一个函数时,它已被执行了0次。因此,在第二行使用它之前,尚未完成require操作。(我们仍处于编译时。)编译器需要知道'c-set'是什么。
我认为我现在理解到这步。但是,我不明白为什么在宏中将require包裹起来,使得`c-set`的使用变得可行。
唯一的区别是它在宏展开时被执行。(宏通常是代码到代码的函数,但在这个情况下,它用于调用require的副作用。)如果你想要使用这样的定义构建AOT编译的库,这可能不是你的解决方案。它在小型的REPL环境(Immediate Mode)中是可以工作的。

注意:我对您的最终使用案例并不完全理解。
by
谢谢。我觉得我需要思考一下宏展开的时间。=)

我的用例是在ClojureScript中(或者更准确地说,在Node.js环境中的SCI)中,我需要在promise解析后延迟一个require操作。我还没有在那里尝试这个解决方案,但我会尝试这个方案并报告我的情况。现在,我正在使用@Imre的解决方案,这对我目前的使用案例来说是合适的,但我还是想试一下这个方案。
by
抱歉,但我的伪宏黑客攻击在这个案例中不起作用,尽管在REPL中它给出了好结果。Imre是对的。
by
实际上,在我的用例中它是可行的。仅供了解。(我会坚持使用Imre的解决方案,但无论如何。)
...