如何为Shape创建表面函数 - 使用数据类型Radius声明的圆?

时间:2012-07-20 06:46:03

标签: haskell types typeclass

下面的Haskell代码工作正常。

data Point = Point Float Float deriving (Show)  
data Shape = Circle Point Float  
surface :: Shape -> Float  
surface (Circle _ r) = pi * r ^ 2  

结果:

*Main> surface $ Circle (Point 0 0) 10  
314.15927  

下面的Haskell代码不起作用。为什么?如何正确编写Shape - Circle的表面函数?

data Point = Point Float Float deriving (Show)  
data Radius = Radius Float deriving (Show)

data Shape = Circle Point Radius   

surface :: Shape -> Float  
surface (Circle _ (Radius r)) = pi * (Radius r) ^ 2

3 个答案:

答案 0 :(得分:2)

你的最后一行是构建一个Radius对象并将其提升为一个权力。由于您尚未定义Radius的幂运算符,因此无效。删除构造函数调用:

surface (Circle _ (Radius r)) = pi * r ^ 2

答案 1 :(得分:1)

有两个修复。一个就像你写的第一段代码一样:在实际计算位中使用Float而不是Radius

surface :: Shape -> Float
surface (Circle _ (Radius r)) = pi * r ^ 2

另一种是查看(^)的类型:

(^) :: (Num a, Integral b) -> a -> b -> a

...并观察到Radius r ^ 2工作,我们需要一个实例Num Radius。此外,结果将是Radius类型的值(不是Float),因此surface的类型签名必须更改为匹配。易:

newtype Radius = Radius Float deriving (Num, Show)

surface :: Shape -> Radius -- weird looking type
surface (Circle _ r) = pi * r ^ 2
surface (Circle _ (Radius r)) = pi * Radius r ^ 2 -- equivalent

答案 2 :(得分:1)

您只需使用(,)代替PointFloat代替Radius

您还可以将Shape定义为一个类。所以代码将是

type Point = (Float, Float)
data Circle = Circle { center :: Point, radius :: Float }

class Shape a where
  surface :: a -> Float

instance Shape Circle where
  surface c = pi * (radius c) ** 2

这是一种可能的实现方式,只需尝试一下〜