因使用“打印”而导致类型不明确的类型变量“ b1”

时间:2019-02-25 11:26:08

标签: haskell

我有以下无法编译的代码段:

{-# LANGUAGE OverloadedStrings, TypeFamilies, MultiParamTypeClasses #-}

module Main where


class Add a b where 
    type SumTy a b
    plus :: a -> b -> SumTy a b

instance Add Integer Double where
    type SumTy Integer Double = Double
    plus x y = fromIntegral x + y

instance Add Double Integer where
    type SumTy Double Integer = Double
    plus x y = x + fromIntegral y

main :: IO ()
main = do

  print $ plus (5::Integer) 6
  print $ plus (5.0::Double) 6.0

错误消息是:

app/Main.hs:25:3: error:
    • Ambiguous type variable ‘b1’ arising from a use of ‘print’
      prevents the constraint ‘(Show
                                  (SumTy Integer b1))’ from being solved.
      Probable fix: use a type annotation to specify what ‘b1’ should be.
      These potential instances exist:
        instance Show BS.ByteString
          -- Defined in ‘Data.ByteString.Internal’
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        ...plus 24 others
        ...plus 22 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of a 'do' block: print $ plus (5 :: Integer) 6
      In the expression:
        do print $ plus (5 :: Integer) 6
           print $ plus (5.0 :: Double) 6.0
      In an equation for ‘main’:
          main
            = do print $ plus (5 :: Integer) 6
                 print $ plus (5.0 :: Double) 6.0
   |
25 |   print $ plus (5::Integer) 6
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^

使用“打印”产生的歧义类型变量“ b1”是什么意思?我看不到b1的任何地方。

2 个答案:

答案 0 :(得分:4)

plus (5::Integer) 6

第一个参数的类型为Integer。第二个数字的类型可以是任何数字类型,我们假设b1Num b1。因此,我们正在调用该函数

plus :: Integer -> b1 -> SumTy Integer b1

,但是周围没有匹配的实例。 Add Integer Double只有一个实例,但是我们不能调用该实例,因为毕竟程序员以后可能还会为Add Integer Integer添加另一个实例,我们需要为该实例做好准备。 (请注意,其他实例甚至可能位于另一个模块中,因此,GHC不能简单地假设不检查所有 all 模块就不会存在该实例,这将是低效率的。)

您需要为6参数指定类型,否则调用将不明确。

答案 1 :(得分:3)

plus (5 :: Integer) 6

编译器尝试推断6的类型,但失败。您必须明确指定数字文字的类型,例如:

plus (5 :: Integer) (6 :: Double)

为了编译第二条plus语句,您不能传递6.0,因为此值是FloatDouble,并且您没有为Add定义的Double Double的实例。如果需要的话,可以将其类型指定为Integer

plus (5.0 :: Double) (6 :: Integer)