在Haskell中创建一个作用于不同类型的方法

时间:2014-11-11 01:48:21

标签: haskell pattern-matching

我正在尝试在列表中使用不同的数据类型。 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)

但是我得到编译时错误!

2 个答案:

答案 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