2010-07-15 87 views
2

的,我試圖讓下面的代碼編譯推導型多參數類型的類

import IO 

data MyInt = MyInt Int 
data MyString = MyString String deriving Show 

class Show b => MyClass a b where 
    fn :: a -> b 

instance MyClass MyInt MyString where 
    fn (MyInt i) = MyString (show i) 

myprint :: (MyClass a b) => a -> IO() 
myprint a = putStrLn $ show (fn a) 

main = myprint (MyInt 3) 

ghc Main.hs -XMultiParamTypeClasses。但是,編譯器無法推導出b類型變量(在本例中爲MyString)的類型。我怎樣才能將這些信息明確地告訴編譯器?

回答

5

你已經違反了「開放世界」的假設。在這種情況下,範圍中只有一個實例可以滿足類型約束;但是這不是一個非常明確的方式來指定myprint 3的含義,是嗎?考慮到實例可以真正從任何模塊浮動,我們可以看到開放世界的假設如何保護您免受模塊添加或更新時意外的類型/行爲更改。

在這種情況下,您可以嘗試函數依賴關係或鍵入系列。

class Show b => MyClass a b | a -> b where 
    ... 
3

爲了擴大對傑森的回答有點:

class Show b => MyClass a b | a -> b where 
    ... 

意味着b功能取決於a;也就是說,這個類不能有兩個同樣的a和不同的b s。

3

除了函數依賴關係,您可以使用與前者相同的類型族(至少在理論上),但似乎變成了更有利的類型關係定義形式。 在這種情況下,甚至可以避免使用多參數類型:

{-# LANGUAGE TypeFamilies #-} 

data MyInt = MyInt Int 
data MyString = MyString String deriving Show 

class MyClass a where 
    type Showable a :: * 
    fn :: a -> Showable a 

instance MyClass MyInt where 
    type Showable MyInt = MyString 
    fn (MyInt i) = MyString (show i) 

myprint a = putStrLn $ show (fn a) 

main = myprint (MyInt 3)