2013-06-02 34 views
6

我試圖理解爲什麼Haskell的show將 視爲一個不同於列表的字符列表。整數 即使沒有FlexibleInstances Pragma。Haskell如何爲類型實例選擇方法?

已經通過Show文檔閱讀,我意識到 ,我真的不明白的Haskell如何選擇類型的類的實例方法 。

考慮下面的代碼:

class MyShow a where 
    myShow :: a -> String 
    myShowList :: [a] -> String 
    myShowTuple :: (a, b) -> String 

    myShowList xs = "Default List Implementation" 
    myShowTuple t = "Default Tuple Implementation" 

instance MyShow Char where 
    myShow c = "One Char" 
    myShowList xs = "List of Chars" 
    myShowTuple t = "Char Tuple" 

instance MyShow Int where 
    myShow n = "One Int" 
    myShowList xs = "List of Integers" 
    myShowTuple t = "Int Tuple" 

instance MyShow Float where 
    myShow n = show n 

instance (MyShow a) => MyShow [a] where 
    myShow = myShowList 

instance (MyShow a) => MyShow (a, b) where 
    myShowTuple t = "foo" 
    myShow = myShowTuple 

現在,如果我打電話例如

myShow (5::Int,5::Int) 

我預計哈斯克爾認爲 「哦,myShow有一個元組作爲參數。我們來看看哪個 實現。「 ,並選擇最後一個作爲回報會導致 在"foo"。顯然,情況並非如此。 Haskell似乎在查看元組的內容(即 的類型爲a)並決定調用相應的方法, 導致"Int Tuple"

這是爲什麼?

回答

9

當你編寫myShow (5::Int, 5::Int)時,Haskell 確實是說:「哦,myShow有一個元組作爲參數,讓我們看看我需要調用哪個實現。並且它確實選擇最後一個,即myShow = myShowTuple。但這並不意味着結果將是「富」。這意味着致電myShow (5::Int, 5::Int)的結果將與致電myShowTuple (5 :: Int, 5 :: Int)的結果相同。

所以現在Haskell必須決定它需要調用哪個版本的myShowTuple。由於myShowTuple的類型爲MyShow a => (a, b) -> String,因此在倒數第二行中定義的myShowTuple版本的類型爲MyShow a => ((a, c), b) -> String,因此不適用。第17行定義的類型爲(Int, b) -> String,因此適合。這就是挑選的那個。

+0

謝謝您的回答,但我還是不明白,爲什麼在第二到最後一行'myShowTuple'已鍵入'(( a,c),b)'因爲元組不是MyShow的唯一實例。 – Aton

+1

@Aton(重命名類型變量以避免歧義)。因爲在MyShow t的類定義中有'myShowTuple ::(t,t2) - > String',並且在第二行到最後一行,你在MyShow(a,b)'的實例定義中,所以't'是'(a,b)',因此'(t,t2) - > String'變爲'((a,b),t2) - > String'。 – sepp2k

3

Haskell的思維過程是這樣的:

  1. 它試圖弄清楚的MyShow的實例(5 :: Int, 5 :: Int)(Int, Int)
  2. 它然後查找實例MyShow a => MyShow (a, b)
  3. 由於這個統一,(a = >ab =>a)它選擇這個實例。
  4. 它檢查以確保a,在這種情況下,Int,也是它的實例MyShow,它是。注意:在實例被選中後,檢查發生在之後。
  5. myShow (5 :: Int, 5 :: Int)通話的元組的myShow,成爲myShowTuple (5 :: Int, 5 :: Int)
    • 它不叫myShowTuple因爲它們的類型(a, b),並在元組的情況下,a(a, b)所以myShowTuple有型((a, b) ,c)這顯然是不匹配。
  6. 這有型MyShow a => (a, b) -> String),自a在這種情況下有式Int哈斯克爾解決此向MyShow
  7. Int例如,它運行相應myShowTuple
  8. 你得到"Int Tuple"

只是一個旁註,如果這是一個Show的實際實施,你會想要這樣的myShowTuple

myShowTuple :: MyShow b => (a, b) -> String 

否則你沒有辦法以實際的格式,b這是畢竟,任何類型。

這將使

instance (MyShow a) => MyShow (a, b) where 
    ... 

instance (MyShow a, MyShow b) => MyShow (a, b) where 
    ...