Kar*_*ran 1 haskell instance typeclass
我有一个"Shape"类,它应该在所有实例上定义"area".area返回"区域b"(数据类型),其中包含一个数字(b属于Num类型类),表示该Shape的区域.
Haskell有问题将b绑定到(x*y),其中x和y的类型为'a',而'a'也是类型类型Num.我该如何解决这个问题?[如果我将(x*y)替换为0,它可以工作,但即使用(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
Run Code Online (Sandbox Code Playgroud)
错误:
[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.
Run Code Online (Sandbox Code Playgroud)
这里的问题是area类型签名:
area :: (Num b) => a -> Area b
Run Code Online (Sandbox Code Playgroud)
什么它说的是"给我a,我会给你一个Area b对任何 b你想,你可以选择".所以,举例来说,我可以给area的Integer,并希望回来的Area Double.显然,这不是你想要的!
在这种情况下,错误的出现是因为你使用x*y,其类型为一,当b预期-你必须给,对工作的价值的任何数字类型b,但是你给的值仅适用于一个(一) .
如果你改变了area类型a -> Area Integer,那么它会起作用.但是,我有一种感觉,您希望实例能够指定区域的类型.为此,您需要使用名为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
Run Code Online (Sandbox Code Playgroud)
这是说,对于每一个类型一个这是一个实例Shape,有一个相关联的类型 AreaComponent a,代表其区域的每个组件的类型.该类型必须是Num定义的实例Shape.
如果您的所有形状都采用数字类型参数,那么您可以做的另一件事是使实例适用于每个形状的类型构造函数,而不是完整的形状类型本身:
class Shape sh where
area :: (Num a) => sh a -> Area a
instance Shape Rectangle where
area (Rectangle x y unit) = Area (x*y) unit
Run Code Online (Sandbox Code Playgroud)