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

时间:2013-06-02 17:03:38

标签: haskell typeclass

我试图理解为什么Haskell的show会对待 与例如列表不同的字符列表整数 即使没有FlexibleInstances Pragma。

阅读了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)

我希望Haskell能够思考 '哦,myShow有一个元组作为参数。我们来看看哪个 执行我必须打电话。' 并选择最后一个会产生的结果 在"foo"。 显然,事实并非如此。 Haskell似乎在研究元组的内容(即 a)的类型并决定调用相应的方法, 结果为"Int Tuple"

为什么会这样?

2 个答案:

答案 0 :(得分: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,因此一个适合。所以这就是被选中的那个。

答案 1 :(得分:4)

Haskell的思维过程是这样的:

  1. 它试图找出MyShow(5 :: Int, 5 :: Int)
  2. (Int, Int)实例
  3. 然后找到实例MyShow a => MyShow (a, b)
  4. 由于此统一,(a => ab => a),它会选择此实例。
  5. 检查以确保a,在这种情况下Int,也是MyShow的实例。注意:在选择实例后,此检查会发生
  6. myShow (5 :: Int, 5 :: Int)调用元组的myShow并成为myShowTuple (5 :: Int, 5 :: Int)
    • 它不会调用myShowTuple,因为它的类型为(a, b),而在元组的情况下,a(a, b)所以myShowTuple的类型为((a, b) ,c) {1}}显然不匹配。
  7. 这个类型为MyShow a => (a, b) -> String),因为在这种情况下a类型为Int haskell将此解析为Int MyShow的实例
  8. 运行相应的myShowTuple
  9. 你得到"Int Tuple"
  10. 只是一个旁注,如果这是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
      ...