我正在尝试在列表中使用不同的数据类型。 e.g:
data Shape = Square Int
| Circle Int
| Rectangle Int Int
| Triangle Int Int Int
deriving (Show)
shapes = [Square 5, Circle 2, Rectangle 10 5]
showShapes :: [Shape] -> [Int]
showShapes [] = []
showShapes (s:xs) = getArea (s : xs)
但是我正在努力创建方法“getArea”,因为我需要为每种不同类型创建一个。我不知道使用参数模式匹配的方法。有没有办法做到这一点,还是我以错误的方式处理这个问题?
如何使用if语句和“typeOf”函数
来完成它我尝试将Shape更改为:
data Shape = Square Int
| Rectangle Int Int
| Triangle Int Int Int
deriving (Show, Typeable)
但是我得到编译时错误!
答案 0 :(得分:4)
对于你的简单情况,只需在getArea
中使用模式匹配,但是你必须将你的值转换为双精度,因为当你有一个整数时,圆的面积永远不会是一个整数半径:
getArea :: Shape -> Double
getArea (Square l) = fromIntegral $ l * l
getArea (Circle r) = pi * fromIntegral r ^ 2
getArea (Rectangle l w) = fromIntegral $ l * w
-- assuming the constructor takes the 3 side lengths
getArea (Triangle a b c) = sqrt $ p * (p - a') * (p - b') * (p - c')
where
[a', b', c'] = map fromIntegral [a, b, c]
p = (a' + b' + c') / 2
虽然我不知道你想在showShapes
做什么。通常,Haskell中的单词show
与其他语言中的toString
意思相同,但您尝试在其中应用getArea
。无论如何,showShapes
的模式匹配已关闭,您需要在s:xs
附近使用括号,否则您将收到语法错误,并且您无法在列表前面添加数字与Shape
一样getArea s : xs
。相反,您可能想要计算列表中每个形状的面积?为此,您可以使用map
:
getAreas :: [Shape] -> [Double]
getAreas shapes = map getArea shapes
答案 1 :(得分:1)
请注意,在这种情况下,您不需要将所有数据存储在一种数据类型中。您可以改为使用存在量化:
{-# LANGUAGE ExistentialQuantification #-}
data Square = Square Int
data Circle = Circle Int
data Rectangle = Rectangle Int Int
class HasArea a where
area :: a -> Double
instance HasArea Square where
area (Square n) = fromIntegral n * fromIntegral n
instance HasArea Circle where
area (Circle r) = pi * fromIntegral r ^ 2
instance HasArea Rectangle where
area (Rectangle n m) = fromIntegral n * fromIntegral m
data Shape = forall s. HasArea s => Shape s
shapes :: [Shape]
shapes = [Shape (Square 5), Shape (Circle 2), Shape (Rectangle 10 5)]
shapeArea :: Shape -> Double
shapeArea (Shape s) = area s
main = print $ map shapeArea shapes
您可以在此处阅读有关存在量化的信息:http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types
存在量化本身比广义代数数据类型更弱。你可以在这里阅读它们:http://en.wikibooks.org/wiki/Haskell/GADT