为什么Haskell中的这种类型注释是必要的?

时间:2013-07-08 09:18:02

标签: haskell overloading ghc typeclass

我正在研究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调用附近进行类型注释。它适用于两个数字 - 推断这个注释有什么问题?打开这两个扩展名的重载规则是什么?

1 个答案:

答案 0 :(得分:7)

您的代码存在的问题是数字文字本身已经过载。因此,文字6的类型为Num a => a,而my_fun 5的类型为F_third_arg b => b -> Integer。因此在类型推断期间,它统一了这两个类型变量。但由于没有其他要求,GHC无法找到在这里使用的具体类型,并给出了相应的错误信息:

test.hs:16:26:
    No instance for (F_third_arg a0) arising from a use of `my_fun'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance F_third_arg String -- Defined at test.hs:9:10
      instance F_third_arg Integer -- Defined at test.hs:6:10
    In the expression: (my_fun 5)
    In the first argument of `show', namely `((my_fun 5) $ 6)'
    In the second argument of `($)', namely `show ((my_fun 5) $ 6)'

test.hs:16:38:
    No instance for (Num a0) arising from the literal `6'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus three others
    In the second argument of `($)', namely `6'
    In the first argument of `show', namely `((my_fun 5) $ 6)'
    In the second argument of `($)', namely `show ((my_fun 5) $ 6)'

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

你找到了一种方法来修复它,但@ leftroundabouts建议使用F_third_arg Double更好一些。