2009-12-09 87 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#中繼承......除非......我對擴展性有特別的關注。

你不是使用差異聯合來建模任何級別的繼承......你在比較蘋果和胡蘿蔔。

你可以在兩種範例中對相同的需求建模......我會在你的上下文中區分歧異的工會......我認爲它會使代碼更容易閱讀......但這是主觀的。