clojure中的模式比使用实例更惯用?发文

clojure中的模式比使用实例更惯用?发文,clojure,polymorphism,Clojure,Polymorphism,我尝试实现以下模式:我有一个AST和两个生成器,一个用于C#,一个用于VB。生成器将提供的AST作为输入,并以所选语言生成源代码。首先,我定义了生成器的抽象: (defprotocol Generator (generate-code [this ast])) 然后我给出一个实现,一个用于C,一个用于VB(我只给出C实现,因为VB实现几乎完全相同): 我不喜欢在gen csharp函数中使用instance?。在Clojure中有没有更惯用的方式来编写这种类型的分派?您可以颠倒抽象: (d

我尝试实现以下模式:我有一个AST和两个生成器,一个用于C#,一个用于VB。生成器将提供的AST作为输入,并以所选语言生成源代码。首先,我定义了生成器的抽象:

(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)))