分享您的想法,参与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场景。关于此问题的一个详细描述在ClojureDoks中可找到。

在可能的情况下,另一个更喜欢使用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 包裹在宏中可以让 `c-set` 的使用工作。
唯一的区别是它在宏展开时执行。在这个情况下,宏通常是一个从代码到代码的函数,但在这个案例中,它是用来调用 require 的副作用。如果您想构建一个使用这些定义的前端编译(AOT)库,这可能不是解决问题的方法。在交互式环境(REPL)中它是可行的。

注意:我对您的最终用途并不是非常理解。
谢谢。我觉得我需要思考一下宏展开时的情况。=)

我的用例是在ClojureScript中(或者更准确地说是在nodejs环境中SCI)中,我需要在Promise解析之后再执行require。我还没有尝试过这个解决方案,但我将尝试它并反馈我的进展。现在,我正在使用Imre的解决方案,这对于我的用例来说已经足够好了,但我还是想试一试这个方法。
by
对不起,但我的伪宏技巧在这个情况下并不适用,尽管它在REPL中给出了良好的结果。Imre是对的。
by
实际上它在我的用例中是有效的。顺带一提。(我还是会坚持使用Imre的解决方案,但是无论如何。)
...