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

在Haskell中创建一个作用于不同类型的方法,haskell,pattern-matching,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] -> [I

我试图在列表中使用不同的数据类型。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”函数来实现它

我试着把形状改成这样:

data Shape = Square Int
            | Rectangle Int Int
            | Triangle Int Int Int
                 deriving (Show, Typeable)

但是我得到了一个编译时错误

对于您的简单情况,只需在
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
周围加上括号,否则会出现语法错误,并且不能像
getArea s:xs
那样在
Shape
列表前面加上数字。相反,您可能希望计算列表中每个形状的面积?为此,您可以使用
map

getAreas :: [Shape] -> [Double]
getAreas shapes = map getArea shapes

对于您的简单情况,只需在
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
周围加上括号,否则会出现语法错误,并且不能像
getArea s:xs
那样在
Shape
列表前面加上数字。相反,您可能希望计算列表中每个形状的面积?为此,您可以使用
map

getAreas :: [Shape] -> [Double]
getAreas shapes = map getArea shapes

注意,在这种情况下,不需要将所有图形存储在一个数据类型中。您可以改为使用存在量化:

{-# 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
您可以在此处阅读关于存在量化的内容:


存在量化本身比广义代数数据类型弱。您可以在这里阅读它们:

注意,在本例中,您不需要将所有图形存储在一个数据类型中。您可以改为使用存在量化:

{-# 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
您可以在此处阅读关于存在量化的内容:



存在量化本身比广义代数数据类型弱。您可以在这里阅读有关它们的信息:

非常感谢。只是原始问题的一个扩展,您将如何使用if语句和“typeOf”函数来实现它。函数typeOf shapes似乎不起作用。@YahyaUddin
typeOf
的类型是什么?这听起来像是家庭作业,你试过什么?请记住,SO不是一个让别人帮你做作业的论坛。这不是我家庭作业的一部分。哈哈。我会编辑我的帖子来展示我所做的。注意:
getArea(圆圈r)=pi*fromIntegral r
@gallais中有一个拼写错误。这是我写一个快速答案时发生的情况。非常感谢。只是原始问题的一个扩展,您将如何使用if语句和“typeOf”函数来实现它。函数typeOf shapes似乎不起作用。@YahyaUddin
typeOf
的类型是什么?这听起来像是家庭作业,你试过什么?请记住,SO不是一个让别人帮你做作业的论坛。这不是我家庭作业的一部分。哈哈。我会编辑我的帖子来展示我的尝试。注意:
getArea(圆r)=pi*fromIntegral r
@gallais中有一个拼写错误。这是我写快速答案时发生的情况。“但我得到了一个编译时错误!”-那是什么错误?不知道出了什么问题就很难诊断问题!这里没有将不同的数据类型放在列表中。您只有一种数据类型:
Shape
。形状有4种不同的情况,而参数模式匹配正是您判断情况的方式。使用
typeOf
在这里没有意义。哦,对了,这是有意义的。非常感谢“但是我得到了一个编译时错误!”-那是什么错误?不知道出了什么问题就很难诊断问题!这里没有将不同的数据类型放在列表中。您只有一种数据类型:
Shape
。形状有4种不同的情况,而参数模式匹配正是您判断情况的方式。使用
typeOf
在这里没有意义。哦,对了,这是有意义的。实际上,这是一种反模式:
[Shape]
所传递的信息并不比
[Double]
多,因为给定一个
形状
你唯一能做的就是计算它的
面积
@chi我想说,这里存在主义的唯一真正用途是,你可以在列表上映射
shapeArea
,而不必在列表的每个元素上调用
shapeArea
。根据具体情况,这可能有助于减少键入和冗余,但实际上,它只用于创建一个从未使用过的中间结构,只用于在其上映射函数的结果。如果我的列表中有50个形状,这将使我的生活更加轻松,我的代码也更加清晰,但它不会比
[Double]
更有用。@chi,我不同意。首先,你引用的这篇文章的作者说“这实际上只是一个符号上的差异”。符号差异不是反模式。其次,
toWidget::Window->Widget
实际上是
windowToWidget::Window->Widget
<代码>收音机按钮小部件