2011-12-15 81 views
3

假設我有一個簡單的類AClass,其中有一個公共成員f1,它可以被覆蓋。與另一個成員f2定義AClass的新實例的方法有哪些,但缺少複製源代碼AClass的方法?下面玩具代碼:用新成員覆蓋類實例

class AClass a where 
    f1 :: a -> Int 

data Val = I Int 

instance AClass Val where 
    f1 x = 0 

    -- the method below can't be added as it is not public member of AClass 
    -- f2:: a -> Float 
    -- f2 x = 0.0 

我環顧四周,但我沒有找到如何做到這一點任何明顯的例子(即例子我能理解以及 - 透明度是相對的)。有什麼可能的方法?關閉,新類型聲明還是別的?用上面的玩具編碼演示技術會很有幫助 - 您可以更改data聲明等(例如,用的newtype包裝替換它),但上面代碼中唯一不可變的是類聲明AClass。這是因爲這個假設是這個類已經被一個圖書館作者編寫了,所以我不能碰它。最終的結果應該是繼承AClass的好處,並增加f2成員的另一個玩具代碼。

當然會有一些注意事項,在這樣的重寫類中。但是,它有助於瞭解什麼是可能的,以及如何。

- 更新 -

下面的工作代碼 - 感謝Ben和mergeconflict能想出解決方案 - 很少有缺件 - 下面填寫:

class AClass a where 
    f1 :: a -> Int 

class (AClass a) => BClass a where 
    f2 :: a -> Float 

data Val = I Int 

instance AClass Val where 
    f1 _ = 0 

instance BClass Val where 
    f2 _ = 0.0      

回答

9

你想達到什麼目的?

你有一個類型Val,你做了一個AClass的實例。您可以定義任何數量的使用Val的功能,這些功能與課程無關。只需停止嘗試在instance聲明中定義它們。

如果你期待的是能夠擁有AClass有一個額外的f2功能,然後您可以在使用AClass情況下,讓他們能夠調用f2函數使用一個特定的實例...這是荒誕。根據定義,所有AClass實例通用的唯一事物是AClass中聲明的事物。如果你所知道的一些價值是它是一個AClass實例類型的成員,那麼你無法對它做任何事情,你不能對AClass的所有實例做任何事情。你不能調用任何額外的東西,特定於某些實例。

如果你想創建一個支持所有的操作是AClass確實還有一個f2,並有Val是新的類的實例...那麼你只要做到這一點。

class AClass a => AnotherClass a where 
    f2 :: a -> Float 

instance AnotherClass Val where 
    f2 x = 0.0 
+0

@ dave4420:感謝編輯示例 – Ben 2011-12-15 06:06:33

+0

是的,支持AClass操作的類,並且f2可以工作。但是,如果我嘗試你的方法,我會得到有關f1不是AnotherClass的可見成員的錯誤。實例f1和f2留給實例,這就是錯誤的來源。 – Sal 2011-12-15 11:58:23

4

你應該請記住,Haskell不是面向對象的,Haskell類型類不像面向對象意義上的類。

您可以簡單地定義一個函數f2 _ = 0.0。它不會是類型類AClass的成員,除非將它添加到定義中 - 但爲什麼需要它?

+0

謝謝。爲了澄清,我不是從面向對象的角度來問。問題是關於Haskell中的可能性以及如何。 – Sal 2011-12-15 03:30:33

5

你的問題並沒有真正意義哈斯克爾:

說我有一個簡單的類AClass與可覆蓋的公共成員f1

如果你正在考慮「公共成員」可以「覆蓋」的「類」,你在考慮面向對象的術語。您展示的代碼根本不代表這些概念。見託尼·莫里斯的帖子"Type-classes are nothing like interfaces."

一個型類定義概念(在C++ sense,有沒有什麼幫助的話)。該概念由一些功能組成,例如:

class Eq a where 
    (==) :: a -> a -> Bool 

...但沒有實際的行爲或實現這些功能。這裏沒有什麼可以「覆蓋」的。數據類型模型這個概念將提供實例聲明,如:

data Integer = {- ... -} 
instance Eq Integer where 
    x == y = x `integerEq` y 

data Float = {- ... -} 
instance Eq Float where 
    x == y = x `floatEq` y 

這樣你就可以實現多態的算法,如:

allEqual :: Eq a => a -> a -> a -> Bool 
allEqual a b c = (a == b) && (b == c) 

現在,又回到了你的問題,你也可以定義類型與某些先前定義的類型類建模的更具體概念的類。例如:

class (Eq a) => Num a where 
    (+), (-), (*) :: a -> a -> a 

那麼,有沒有的Num實例Eq實例,但Num所有實例必須是Eq實例。在你的榜樣,你可能會想是這樣的:

class AClass a where 
    f1 :: a -> Int 

class (AClass b) => BClass b where 
    f2 :: a -> Float 

data Val = {- whatever -} 
instance BClass Val where 
    f1 _ = 0 
    f2 _ = 0.0 

同樣,Val不是「繼承好東西」本身,它只是說,它是BClass一個實例,因而也AClass一個實例。但這顯然是玩具代碼...