在Haskell中创建一个作用于不同类型的方法
我试图在列表中使用不同的数据类型。e、 g:在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
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似乎不起作用。@YahyaUddintypeOf
的类型是什么?这听起来像是家庭作业,你试过什么?请记住,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
<代码>收音机按钮小部件