clojure中的模式比使用实例更惯用?发文
我尝试实现以下模式:我有一个AST和两个生成器,一个用于C#,一个用于VB。生成器将提供的AST作为输入,并以所选语言生成源代码。首先,我定义了生成器的抽象:clojure中的模式比使用实例更惯用?发文,clojure,polymorphism,Clojure,Polymorphism,我尝试实现以下模式:我有一个AST和两个生成器,一个用于C#,一个用于VB。生成器将提供的AST作为输入,并以所选语言生成源代码。首先,我定义了生成器的抽象: (defprotocol Generator (generate-code [this ast])) 然后我给出一个实现,一个用于C,一个用于VB(我只给出C实现,因为VB实现几乎完全相同): 我不喜欢在gen csharp函数中使用instance?。在Clojure中有没有更惯用的方式来编写这种类型的分派?您可以颠倒抽象: (d
(defprotocol Generator
(generate-code [this ast]))
然后我给出一个实现,一个用于C,一个用于VB(我只给出C实现,因为VB实现几乎完全相同):
我不喜欢在
gen csharp
函数中使用instance?
。在Clojure中有没有更惯用的方式来编写这种类型的分派?您可以颠倒抽象:
(defprotocol CodeGenerator
(生成类[此ast])
其他生成方法
)
(defrecord VBGenerator[]
代码生成器
(生成类[此ast](gn vb类ast)))
(defrecord CSharpGenerator[]
代码生成器
(生成类[此ast](gn chsharp类ast)))
然后只编写一次实例?
调用:
(定义发电机代码[发电机ast]
(cond(实例?AstClass ast)(生成类生成器ast)
+其他发电机箱。。。
))
或者可以对gen类的第二个参数使用multimethods。每个多方法定义将从CodeGenerator
调用正确的方法:
(反多基因类(fn[;ast](ast类型)))
(定义方法发电机类AstClass[发电机类ast]
(生成类生成器ast))
或者,您也可以使用无协议的专用多方法
(定义多代代码(fn[语言ast][语言(类型ast)])
这里的第一个参数是一个表示目标语言的关键字,但是,您也可以使用类型
;;csharp定义
(defmethod gen code[:csharp AstClass][[uuast]
(gen chsharp等级ast))
;; vb定义
(定义方法生成代码[:vb AstClass][[uuast]
(通用vb类)
(方法生成代码[:vb AstNumber][[uuast]
...)
...
然后使用节点调用gen代码:
(gen代码:vb(新类…)
Condp()可能也很有用,这里有一个实例?谢谢@erdos。我会看看你所有的建议,看看哪一个最适合我。谢谢@Rulle,我查过condp了。我肯定会开始更多地使用它:)@erdos,没有其他方法可以完全摆脱使用instance?
吗?将此标记为答案,因为这是我选择实现的。但是对于我来说,仅仅使用多种方法的替代方案也很不错:)请注意,你可以使用(defn-gen csharp…
而不是(defn^:private gen csharp…
谢谢@erdos,我更喜欢使用^:private
来保持一致性,因为没有def-
与defn-
一起使用,历史上,defn-
是为方便起见而添加的,^:private
非常容易编写:)
(defn ^:private gen-csharp-class [ast]
(str "class " (:id ast) " { }"))
(defn ^:private gen-csharp [ast]
(cond
(instance? AstClass ast) (gen-csharp-class ast)))
(defrecord AGenerator []
Generator
(generate-code [this ast] (gen-csharp ast)))