我试图理解为什么Haskell会show处理一个不同于整数列表的字符列表,即使没有FlexibleInstancesPragma也是如此.
通读了文档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
Run Code Online (Sandbox Code Playgroud)
现在如果我打电话,例如
myShow (5::Int,5::Int)
Run Code Online (Sandbox Code Playgroud)
我希望Haskell认为'哦,myShow有一个元组作为一个论点.让我们看看我必须打电话给哪个实施.并选择最后一个将导致的结果"foo".显然,事实并非如此.Haskell似乎在查看元组的内容(即类型a)并决定调用相应的方法,从而产生"Int Tuple".
为什么是这样?
当你写作时myShow (5::Int, 5::Int),Haskell 确实说"哦,myShow有一个元组作为一个参数.让我们看看我必须调用哪个实现." 它确实选择了最后一个,即myShow = myShowTuple.但这并不意味着结果将是"foo".这意味着调用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那个有类型,所以一个确实适合.这就是被选中的那个.