我是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)
| ^
答案 0 :(得分:6)
问题在于, (+) :: Num a => a -> a -> a
和 (*) :: Num a => a -> a -> a
之类的操作要求操作数具有相同类型。您不能将Int
和Integer
一起添加,也不能将Float
与Double
进行倍增。存在一些类似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 b
与Num b
的情况下,有一个inflate :: Num b => MyShape b -> b -> MyShape b
,与area :: Num b => MyShap b -> b
相同。