8

我正在研究 GHC 中的函数重载有多强大。我编写了以下代码:

class F_third_arg a where
  run_f :: (Integer, a) -> Integer

instance F_third_arg Integer where
  run_f (_, x) = x

instance F_third_arg String where
  run_f (x, _) = x

my_fun :: (F_third_arg a) => Integer -> (a -> Integer)
my_fun x = \a -> run_f(x, a)

main :: IO ()
main = putStrLn $ show( ((my_fun::Integer->(Integer->Integer)) 5) $ 6)

(是的,我需要 -XTypeSynonymInstances -XFlexibleInstances)而且我很惊讶编译器需要在调用附近的类型注释my_fun。它适用于两个数字——推断这个注释有什么问题?开启这两个扩展的重载规则是什么?

4

1 回答 1

7

您的代码的问题是数字文字本身已经超载。所以文字6有类型Num a => a,而my_fun 5有类型F_third_arg b => b -> Integer。所以在类型推断时,它统一了这两个类型变量。但由于对它们没有其他要求,GHC 在这里找不到要使用的具体类型,并给出适当的错误消息:

测试.hs:16:26:
    没有因使用“my_fun”而产生 (F_third_arg a0) 的实例
    类型变量“a0”不明确
    可能的修复:添加修复这些类型变量的类型签名
    注意:有几种可能的情况:
      instance F_third_arg 字符串——在 test.hs:9:10 定义
      instance F_third_arg 整数——在 test.hs:6:10 定义
    在表达式中:(my_fun 5)
    在`show'的第一个参数中,即`((my_fun 5) $ 6)'
    在`($)'的第二个参数中,即`show ((my_fun 5) $6)'

测试.hs:16:38:
    (Num a0) 没有由文字“6”产生的实例
    类型变量“a0”不明确
    可能的修复:添加修复这些类型变量的类型签名
    注意:有几种可能的情况:
      instance Num Double -- 在 `GHC.Float' 中定义
      instance Num Float -- 在 `GHC.Float' 中定义
      instance Integral a => Num (GHC.Real.Ratio a)
        -- 在“GHC.Real”中定义
      ...加上另外三个
    在‘($)’的第二个参数中,即‘6’
    在`show'的第一个参数中,即`((my_fun 5) $ 6)'
    在`($)'的第二个参数中,即`show ((my_fun 5) $6)'

人们可能期望编译器注意到这Integer是唯一同时满足这两个要求的类型,但是这种启发式方法会使您的代码相对脆弱,即它会因为您添加一个新实例(例如F_third_arg Double)而中断。因此编译器会拒绝该代码并要求您明确说明所讨论的类型。

您找到了一种解决方法,但@leftroundabouts 的使用建议6::Integer更好一些。

于 2013-07-08T10:35:34.727 回答