2016-09-22 68 views
0

我写一个“简单”的例子执行但我有一个很难搞清楚为什么这个不能编译类型类:无法比拟预期类型的​​实例

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)

回答

3

让我们来仔细看一下在类的定义中引用的类型:

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

在第二行中的aa在第一线的约束。但b不受任何约束,所以它是隐含普遍量化的。换句话说,上面的定义等同于

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

所以对于每Euclideana类型,norm是函数,其采用a值,并返回任何Floating b一个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约束,这样我可以调用realToFracx获得任意浮点值。请注意,用RealFrac代替Floating限制可能会更有意义。

+0

感谢您的及时答复。现在还有一个问题:我怎样才能将'x'的类型与'y'的类型相匹配? 我写了实现为 'norm(Point xy)= realToFrac $ sqrt $(x * x)+(y * y)' (在实例头文件中增加了Real约束到两种类型),但现在它抱怨它不能与'y'匹配'x' – Midiparse

+0

尝试类似于'instance(Real x,Floating x)=> Euclidean(Point xx)其中' – redneb

+0

它抱怨它需要不同的类型变量,并且添加FlexibleConstraints以允许这个 – Midiparse

相关问题