【发布时间】:2016-06-21 15:55:21
【问题描述】:
我想编写函数而不考虑函数声明的顺序,我不想使用 declare 函数,因为我需要声明所有我不想这样做的函数名.
我想要一些能为我带来魔力的宏或函数。长话短说,我需要编写像Java这样的函数(方法声明顺序无关重要)
【问题讨论】:
标签: clojure clojurescript
我想编写函数而不考虑函数声明的顺序,我不想使用 declare 函数,因为我需要声明所有我不想这样做的函数名.
我想要一些能为我带来魔力的宏或函数。长话短说,我需要编写像Java这样的函数(方法声明顺序无关重要)
【问题讨论】:
标签: clojure clojurescript
我最喜欢函数式编程的最好的一点是,它的写作流程与思维流程相同。就像剥洋葱一样,每时每刻,我只需要集中精力在这一层上,把里面的部分视为理所当然。并且不要担心函数名称,foo 和 bar 一开始会很好。在这种写作风格中,函数是从源文件的末尾到顶部定义和实现的。在一个函数调用多个其他函数的情况下,这种线性结构变成了树状结构,但文件中总是有一个点可以插入新函数。没有选择和担忧。
是的,有时我们需要处理一些没有其他依赖关系的代码 sn-ps。它们当然可以放在源文件的顶部。
要提前回答这个问题,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,无需考虑函数的顺序。不过,我不会在生产中这样做(至少在没有大量测试的情况下不会这样做)。
【讨论】:
def 表单或扩展为defn 或defn- 表单的其他宏。