Я пытаюсь использовать в списке разные типы данных. например:
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)
Но я получаю ошибку времени компиляции!
2 ответа
В вашем простом случае просто используйте сопоставление с образцом в 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
. Обычно слово show
в Haskell означает то же самое, что и toString
в других языках, но вы пытаетесь применить getArea
внутри него. Несмотря на это, сопоставление с шаблоном для showShapes
отключено, вам нужны скобки вокруг s:xs
, иначе вы получите синтаксическую ошибку, и вы не сможете добавить число перед списком Shape
как с getArea s : xs
. Вместо этого вы, возможно, захотите рассчитать площадь для каждой фигуры в списке? Для этого вы можете использовать map
:
getAreas :: [Shape] -> [Double]
getAreas shapes = map getArea shapes
typeOf
? Похоже, это тоже домашнее задание, что вы пробовали? Пожалуйста, имейте в виду, что SO не является форумом для того, чтобы заставить других делать вашу домашнюю работу за вас.
getArea (Circle r) = pi * fromIntegral r
есть опечатка.
Обратите внимание, что в этом случае вам не нужно хранить все цифры в одном типе данных. Вместо этого вы можете использовать экзистенциальную количественную оценку:
{-# 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/Existenfully_quantified_types
Сама по себе экзистенциальная количественная оценка слабее, чем обобщенные алгебраические типы данных. Вы можете прочитать о них здесь: http://en.wikibooks.org/wiki/Haskell/GADT < / а>
[Shape]
не передает больше информации, чем [Double]
, поскольку при наличии Shape
единственное, что вы можете сделать, это вычислить его area
. lukepalmer.wordpress.com/2010/01/24/…
shapeArea
по списку вместо того, чтобы вызывать shapeArea
для каждого отдельного элемента списка. Это может быть полезно для уменьшения количества типизации и избыточности в зависимости от ситуации, но на самом деле это только для создания промежуточной структуры, которая никогда не используется, а только результат отображения функции на нее. Если бы у меня было 50 фигур в списке, это сделало бы мою жизнь намного проще, а мой код значительно понятнее, но это было бы не более полезно, чем [Double]
.
toWidget :: Window -> Widget
на самом деле windowToWidget :: Window -> Widget
. radio_buttonToWidget
, combo_boxToWidget
... вместо одного Widget
. В-третьих, в более сложных случаях вам все равно понадобится запись вместо безымянного списка двойников. Почему вы должны предпочесть что-то с предварительно вычисленными (семантически предварительно вычисленными из-за лени) значениями? Очевидно, что вы можете снабдить свою запись «методами», но зачем, когда у вас есть эквалайзер?
Похожие вопросы
Новые вопросы
haskell
Haskell — это чисто функциональный язык программирования со строгой статической типизацией, отложенными вычислениями, обширной поддержкой параллелизма и параллелизма, а также уникальными возможностями абстракции.
Shape
. Форма имеет 4 разных случая, и сопоставление шаблонов параметров — это именно то, как вы определяете, какой случай у вас есть. ИспользованиеtypeOf
здесь не имеет смысла.