如何修复Haskell中的“无法匹配预期类型”错误?

时间:2019-06-27 18:16:18

标签: haskell

我是Haskell的新手,现在正在学习类型课程。我创建了一个简单的类型类,但不幸的是我无法修复

  

无法匹配预期的类型

-- So a can be Int, Float etc
data MyShape a = Circle a -- etc like | Rectangle a a 
  deriving(Show)

class Geo a where
  inflate :: Num b => a -> b -> a
  area :: Num b => a -> b

instance Num a => Geo (MyShape a) where
  inflate (Circle r) x = Circle (r * x)
  area (Circle r) = 3 * r * r

它既不喜欢充气功能,也不喜欢面积功能。

错误:

• Couldn't match expected type ‘a’ with actual type ‘b’
      ‘b’ is a rigid type variable bound by
        the type signature for:
          inflate :: forall b. Num b => MyShape a -> b -> MyShape a
        at test2.hs:122:3-9
      ‘a’ is a rigid type variable bound by
        the instance declaration
        at test2.hs:121:10-33
    • In the second argument of ‘(*)’, namely ‘x’
      In the first argument of ‘Circle’, namely ‘(r * x)’
      In the expression: Circle (r * x)
    • Relevant bindings include
        x :: b (bound at test2.hs:122:22)
        r :: a (bound at test2.hs:122:19)
        inflate :: MyShape a -> b -> MyShape a (bound at test2.hs:122:3)
    |
122 |   inflate (Circle r) x = Circle (r * x)
    |                                      ^

1 个答案:

答案 0 :(得分:6)

问题在于, (+) :: Num a => a -> a -> a (*) :: Num a => a -> a -> a 之类的操作要求操作数具有相同类型。您不能将IntInteger一起添加,也不能将FloatDouble进行倍增。存在一些类似fromIntegral :: (Integral a, Num b) => a -> b的转换,但是据我所知,这些转换无法将任意Num类型转换为任意Num类型,并且还可能导致不确定性。例如,通过将Integer转换为Float,可以“丢失数据”。

例如,您的inflate :: (Geo a, Num b) => a -> b -> a函数将导致两种不同类型,即膨胀常数x的类型和圆中值的类型。两者都是Num类型,但本身不是同一类型。

例如,我们可以将MyShape设为类Geo的实例,例如:

class Geo a where
  inflate :: Num b => a b -> b -> a b
  area :: Num b => a b -> b

,然后定义一个实例,例如:

instance Geo MyShape where
  inflate (Circle r) x = Circle (r * x)
  area (Circle r) = 3 * r * r

因此我们在这里指定MyShape bNum b的情况下,有一个inflate :: Num b => MyShape b -> b -> MyShape b,与area :: Num b => MyShap b -> b相同。