2009-12-09 62 views
5

是否有推荐的方式来建模F#中的多个继承级别,假定使用区分的联合?使用歧视联盟建模多个级别的继承

以在C#中像下面这样:

class Expr { } 
class SourceExpr : Expr { } 
class JoinExpr : SourceExpr { } 
class TableExpr : SourceExpr { } 

我在F#做到了这一点:

type SourceExpr = 
    | Join of JoinExpr 
    | Table of TableExpr 

type Expr = 
    | Source of SourceExpr 
    | ... 

有没有更好的办法?这是否提供了与继承相同的多态行为?

回答

8

在没有更多信息的情况下,在这里很难说得太过规范。根据你想要做的事情,使用类层次结构或区分联合(DU)可能更有意义。最常见/最有意义的折衷是,类层次结构是“开放的”,而DU是“封闭的”。也就是说,您可以轻松地将新类型添加到类层次结构中,但添加新操作(基类上的抽象方法)需要更改所有现有类。相比之下,对于DU,您可以轻松添加新的操作(模式与数据类型匹配的功能),但要添加新的案例(子类),您必须重新定义类型并更新所有现有操作以处理新案例。 (这有时被称为“表达式问题”。)

一个典型的例子对DU来说是好的,它是一个编译器;您有一个语言抽象语法树,其中的语言和树结构是固定的,但是您可以在编译器内编写许多不同的树变换操作。一个典型的例子对于类层次结构很有用,它是UI框架;你有一些基类定义了小部件必须提供的所有操作(Draw,Resize,...),但是用户将添加他们自己的具有额外功能的自定义子类型。

+0

我正在研究解析器,所以我认为DU是正确的选择。但有些表达方式似乎是从别人那里继承的。有些函数应该接受Join或Table,它们都是源。还有一些功能可以接受Expr,其中Source是众多选项之一。我不禁想到OO术语,但我想知道是否有更好的方法来模拟这种相对静态的层次结构,同时保持相同类型的多态行为。 – Daniel 2009-12-09 01:47:15

+0

使用类型对它进行建模可以很好地工作。如果您有两种类型的“也”是同一种东西,请添加一个区分它们并使用它的新类型。唯一的缺点是,你将不得不做更多的解构,但模式匹配和主动模式,你需要他们使它非常容忍。我正在做一些相当复杂的递归类型和一个FParsec解析器,它工作得很好。 – 2009-12-10 15:34:58

0

您可以使用F#中的继承对类进行建模,就像您在C#中执行的操作一样。或者...您可以使用区别化的联合对需求进行建模。

不,受歧视的工会不允许采用相同的多态行为,尤其是如果添加新案例,您可能必须修改所有模式匹配。

它有它的优点,但我倾向于在F#中使用歧视联盟编写代码,并在C#中继承......除非......我对扩展性有特别的关注。

你不是使用差异联合来建模任何级别的继承......你在比较苹果和胡萝卜。

你可以在两种范例中对相同的需求建模......我会在你的上下文中区分歧异的工会......我认为它会使代码更容易阅读......但这是主观的。