2014-06-13 75 views
1

我希望創建一個關聯類型族的兩個實例,就像這樣。當然,這不會編譯,我最終在代碼中採用了不同的方法。不過,我仍然對這個用例感到好奇。我認爲理論上編譯器可以允許這樣做。即使有多個putget的實例可供選擇,結果類型也會清除需要哪個實例。兩種不同方式的類型類的實例

{-# LANGUAGE TypeFamilies #-} 
import Data.Word 

class Genetic g where 
    type Sequence g :: * 
    -- | Writes a gene to a sequence. 
    put :: Sequence g -> g -> Sequence g 
    -- | Reads the next gene in a sequence. 
    get :: Sequence g -> (g, Sequence g) 

data SampleGene = Variant1 | Variant2 deriving Show 

instance Genetic SampleGene where 
    type Sequence SampleGene = [Bool] 
    put xs Variant1 = True : xs 
    put xs Variant2 = False : xs 
    get (True:xs) = (Variant1, xs) 
    get (False:xs) = (Variant2, xs) 

instance Genetic SampleGene where 
    type Sequence SampleGene = [Word8] 
    put xs Variant1 = 0 : xs 
    put xs Variant2 = 1 : xs 
    get (0:xs) = (Variant1, xs) 
    get (1:xs) = (Variant2, xs) 
    get _ = error "coding error" 

main = do 
    putStrLn "Working with Bool sequences" 
    let xs = put [] Variant1 :: [Bool] 
    let (g,ys) = get xs :: (SampleGene, [Bool]) 
    putStrLn $ "Read " ++ show g 
    putStrLn "Working with Bool sequences" 
    let xs = put [] Variant1 :: [Word8] 
    let (g,ys) = get xs :: (SampleGene, [Word8]) 
    putStrLn $ "Read " ++ show g 

我的問題是:

  1. 有沒有辦法在Haskell做到這一點? (除了newtype包裝 - 我希望我的庫的用戶能夠直接使用Haskell基本類型。)

  2. 如果不是,爲什麼不呢?也就是說,我違反了什麼規則,或者我打了什麼類型系統的限制?我想在我正在寫的一篇論文中解釋這一點,但我試圖瞭解類型系統如何在隱藏條件下工作。因此,如果您在答案中使用技術術語,那麼我可以在閱讀中瞭解這些術語。

  3. 理論上,未來的Haskell擴展可能允許這樣做,還是它是非啓動器?

我看過In Haskell, is there any way to express that a type should be an instance of a typeclass in more than one way?,這與我的問題非常相似。但是,我的重點是試圖更好地理解類型系統。

+0

我不是100%肯定,但我認爲即使有型的家庭,你會需要使用newtypes,這主要是'newtype'語義的用途,另一個用途是你可以使類型更明顯,比如使用'Network.Socket.PortNumber'而不是'Word16',使得類型簽名更加清晰至於這個論點需要什麼。 – bheklilr

+3

您是否曾嘗試將「Sequence」的類型作爲第二個參數添加到類中? –

+0

@Joachim我沒有嘗試多參數類型的類。這種趨勢似乎是使用類型家庭,但也許這是MPTC可以做某些類型家庭無法做到的事情。 – mhwombat

回答

5

類型族比MPTCs弱一點,因爲它們只表達類型的函數而不是完整的關係。這對於類型推斷具有優勢,並且也是MPTC也有fundeps的原因。所以,我認爲實現這樣的東西不是不可能的,但是它卻落在了typechecker功率/重量比的錯誤一面。

在任何情況下,如果你真正希望這種行爲很容易通過足以向MPTCs有

class Genetic s g where 
    -- | Writes a gene to a sequence. 
    put :: s -> g -> s 
    -- | Reads the next gene in a sequence. 
    get :: s -> (g, s) 

instance Genetic [Bool] SampleGene where 
    put xs Variant1 = True : xs 
    put xs Variant2 = False : xs 
    get (True : xs) = (Variant1, xs) 
    get (False : xs) = (Variant2, xs) 

instance Genetic [Int] SampleGene where 
    put xs Variant1 = 0 : xs 
    put xs Variant2 = 1 : xs 
    get (0 : xs) = (Variant1, xs) 
    get (1 : xs) = (Variant2, xs) 
    get _  = error "boo"