在typeclass实例中错误绑定类型变量 [英] Error binding type variables in instance of typeclass
问题描述
我有一个"Shape"类,应该在所有实例上定义"area".区域返回"Area b"(一种数据类型),其中包含一个数字(b属于Num类型类),表示该Shape的区域.
I have a class "Shape" which should have "area" defined on all instances. area returns "Area b" (a data type) that contains a number (b belongs to Num typeclass) signifying the area of that Shape.
Haskell在将b绑定到(x * y)时遇到问题,其中x和y的类型为"a",而"a"的类型也为Num. 我该如何解决? [如果我将(x * y)替换为0,则可以使用,但即使使用(0 :: Int)也不能使用]
Haskell has problem binding that b to (x*y) where x and y are of type 'a' and 'a' is also of typeclass Num. How do I solve this ?? [If i replace (x*y) by 0, it works but doesn't work even with (0::Int)]
代码:
data Unit = Unit | Meter | CentiMeter deriving Show
data Area a = Area a Unit deriving Show
class Shape a where
area :: (Num b) => a -> Area b
data Rectangle side = Rectangle side side Unit deriving Show
instance (Num a) => Shape (Rectangle a) where
area (Rectangle x y unit) = Area (x*y) unit
错误:
[1 of 1] Compiling Main ( y.hs, interpreted )
y.hs:11:46:
Could not deduce (a ~ b)
from the context (Num a)
bound by the instance declaration at y.hs:10:10-39
or from (Num b)
bound by the type signature for
area :: Num b => Rectangle a -> Area b
at y.hs:11:10-52
`a' is a rigid type variable bound by
the instance declaration at y.hs:10:15
`b' is a rigid type variable bound by
the type signature for area :: Num b => Rectangle a -> Area b
at y.hs:11:10
In the second argument of `(*)', namely `y'
In the first argument of `Area', namely `(x * y)'
In the expression: Area (x * y) unit
Failed, modules loaded: none.
推荐答案
这里的问题是area
的类型签名:
The problem here is area
's type signature:
area :: (Num b) => a -> Area b
它说的是给我一个a
,我会给你一个Area b
,代表你想要的任何 b
;你可以选择".因此,例如,我可以给area
一个Integer
并期望返回一个Area Double
.显然,这不是您想要的!
What it says is "give me an a
, and I'll give you an Area b
for any b
you want; you can pick". So, for instance, I could give area
an Integer
and expect back an Area Double
. Clearly, this isn't what you want!
在这种情况下,由于使用x*y
类型为 a 的x*y
,因此当出现 b 时会出现错误-您必须提供一个适用于任何数字类型 b ,但是您给出的值仅适用于一个( a ).
In this case, the error arises because you use x*y
, which has type a, when b is expected — you have to give a value that works for any numeric type b, but you're giving a value that only works for one (a).
如果将area
的类型更改为a -> Area Integer
,则可以使用.但是,我有一种感觉,您希望 instance 能够指定区域的类型.为此,您需要使用一种名为 类型家族 <的语言扩展名/a>:
If you changed area
's type to a -> Area Integer
, or such, then it would work. However, I have a feeling you want the instance to be able to specify what the type of the area is. For this, you'll need to use a language extension called type families:
{-# LANGUAGE TypeFamilies #-}
class (Num (AreaComponent a)) => Shape a where
type AreaComponent a
area :: a -> Area (AreaComponent a)
instance (Num a) => Shape (Rectangle a) where
type AreaComponent (Rectangle a) = a
area (Rectangle x y unit) = Area (x*y) unit
这表示,对于作为Shape
实例的每个类型 a ,都有一个关联类型 AreaComponent a
,代表其区域中每个组件的类型.根据Shape
的定义,该类型必须是Num
的实例.
This says that for every type a that's an instance of Shape
, there is an associated type AreaComponent a
, representing the type of each component of its area. That type is required to be an instance of Num
by the definition of Shape
.
如果所有形状都带有数字类型参数,您可以做的另一件事是使实例针对每种形状的类型构造函数,而不是针对完整形状类型本身:
Another thing you could do, if all your shapes take a numeric type parameter, is to make the instances be for the type constructors of each shape, rather than the full shape types themselves:
class Shape sh where
area :: (Num a) => sh a -> Area a
instance Shape Rectangle where
area (Rectangle x y unit) = Area (x*y) unit
这篇关于在typeclass实例中错误绑定类型变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!