是否有任何宏(声明除外)用于编写函数而不考虑Clojure中函数声明的顺序

Is there any macro(except declare) for writing functions without think of the order of function declarations in Clojure

我想在不考虑函数声明顺序的情况下编写函数,我不想使用 declare 函数,因为我需要声明所有我不声明的函数名称我不想这样做。

我想要一些对我有魔力的宏或函数。长话短说,我需要编写类似 Java 的函数(方法声明顺序 重要)

我最喜欢函数式编程的一个优点是,它的写作流程与思维流程相同。就像剥洋葱一样,每时每刻,我只需要专注于这一层,而把里面的部分视为理所当然。不要担心函数名称,foobar 一开始就没问题。在这种写作风格中,函数是从源文件的末尾回到顶部定义和实现的。在一个函数调用多个其他函数的情况下,这种线性结构变成了树状结构,但文件中总是有一个点可以插入新函数。没有选择和烦恼。

是的,有时我们需要在没有其他依赖项的情况下处理一些代码片段。当然可以把它们放在源文件的顶部。

提前回答这个问题,macros 并不神奇。如果存在这样的宏,这个宏需要将整个源文件作为输入,分析每个代码块之间的依赖关系,并以正确的顺序重新流动它们。由于词法作用域,依赖分析是非常重要的。这几乎就像编写编译器一样。我不相信这样的宏存在(有人写过),它能做的事情对我来说不是那么大。

它有点不需要,但很容易作为练习(在某种程度上)。您可以编写宏,它会转发声明包含在其中的所有顶级函数:

(defmacro with-forward-declaration [& body]              
  (let [names (keep #(when (#{'defn 'defn-} (first %))
                       (if (map? (second %)) (nth % 2) (second %)))
                    body)]
    `(do (declare ~@names)
         ~@body)))

这就是它的展开方式:

(with-forward-declaration

  (defn ^long ff1 [x] (* 2 (ff2)))

  (println "just to be sure it doesn't eat other forms")

  (defn ^{:name 'xx} ff2 [] (+ 10 (ff3)))

  (defn ff3 [] 101)

  (defn- ff4 [] :x))

将执行以下操作:

(do
  (declare ff1 ff2 ff3 ff4)
  (defn ff1 [x] (* 2 (ff2)))
  (println "just to be sure it doesn't eat other forms")
  (defn ff2 [] (+ 10 (ff3)))
  (defn ff3 [] 101)
  (defn- ff4 [] :x))

因此,如果您将所有命名空间的代码包装到此宏中,它会为您预先声明所有函数。如果你想更深入,比如预先声明所有一些不在顶层的可能的 defns,你可以通过使用 clojure.walk 来更新这个玩具宏来找到这些内部形式。但我猜这个一个就足够了,可以快速玩 clojure,而不用考虑函数的顺序。不过,我不会在生产中这样做(至少在没有大量测试的情况下不会这样做)。