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