Haskell如何为类型类的实例选择方法?

Ato*_*ton 7 haskell typeclass

我试图理解为什么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".

为什么是这样?

sep*_*p2k 9

当你写作时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那个有类型,所以一个确实适合.这就是被选中的那个.