无法匹配实例中的预期类型

时间:2016-09-22 22:24:44

标签: haskell typeclass

我正在编写一个实现类型类的“简单”示例,但是我很难弄清楚为什么这不会编译:

class Euclidean a where
  norm :: (Euclidean a, Floating b) => a -> b

data Point a b = Point a b

instance (Floating x, Floating y) => Euclidean (Point x y) where
  norm (Point x y) = x

失败了:

Couldn't match expected type ‘b’ with actual type ‘x’
  ‘x’ is a rigid type variable bound by
      the instance declaration at src/Simple.hs:10:10
  ‘b’ is a rigid type variable bound by
      the type signature for
        norm :: (Euclidean (Point x y), Floating b) => Point x y -> b
      at src/Simple.hs:11:3
Relevant bindings include
  x :: x (bound at src/Simple.hs:11:15)
  norm :: Point x y -> b (bound at src/Simple.hs:11:3)
In the expression: x
In an equation for ‘norm’: norm (Point x y) = x

注意:理想的功能实现当然是 sqrt $ (x * x) + (y * y)

1 个答案:

答案 0 :(得分:3)

让我们仔细看看类定义中引用的类型:

class Euclidean a where
    norm :: (Euclidean a, Floating b) => a -> b

第二行中的a由第一行中的a绑定。但b不受任何约束,因此它被隐含地普遍量化。换句话说,上面的定义等同于

class Euclidean a where
    norm :: forall b. (Euclidean a, Floating b) => a -> b

因此,对于每个Euclidean类型anorm是一个函数,它接受a值并返回 any <{1}}的值 b

因此,在Floating b的示例中,您提供的Point的虚拟定义始终返回值norm的值,而编译器期望您提供返回值的实现任意x类型。

那你怎么解决这个问题?解决方案是做类似的事情:

Floating

我添加了instance (Real x, Floating x, Floating y) => Euclidean (Point x y) where norm (Point x y) = realToFrac x 约束,以便我可以在Real x上调用realToFrac来获取任意浮动值。请注意,将x约束替换为Floating可能会更有意义。