,
>False
,
>5
, только эти значения не имели полей. Только что мы записали конструктор и связали его поля с именами. Так как для вычисления площади нам нужен только радиус, мы не заботимся о двух первых полях, которые говорят нам, где располагается круг.
>ghci> area $ Circle 10 20 10
>314.15927
>ghci> area $ Rectangle 0 0 100 100
>10000.0
Ура, работает! Но если попытаться напечатать >Circle 10 20 5
в командной строке интерпретатора, то мы получим ошибку. Пока Haskell не знает, как отобразить наш тип данных в виде строки. Вспомним, что когда мы пытаемся напечатать значение в командной строке, интерпретатор языка Haskell вызывает функцию >show
, для того чтобы получить строковое представление значения, и затем печатает результат в терминале. Чтобы определить для нашего типа >Shape
экземпляр класса >Show
, модифицируем его таким образом:
>data Shape = Circle Float Float Float | Rectangle Float Float Float Float
> deriving (Show)
Не будем пока концентрировать внимание на конструкции >deriving (Show)
. Просто скажем, что если мы добавим её в конец объявления типа данных, Haskell автоматически определит экземпляр класса >Show
для этого типа. Теперь можно делать так:
>ghci> Circle 10 20 5
>Circle 10.0 20.0 5.0
>ghci> Rectangle 50 230 60 90
>Rectangle 50.0 230.0 60.0 90.0
Конструкторы значений – это функции, а значит, мы можем их отображать, частично применять и т. д. Если нам нужен список концентрических кругов с различными радиусами, напишем следующий код:
>ghci> map (Circle 10 20) [4,5,6,6]
>[Circle 10.0 20.0 4.0,Circle 10.0 20.0 5.0,Circle 10.0 20.0 6.0,Circle 10.0 20.0 6.0]
Верный способ улучшить фигуру
Наш тип данных хорош, но может быть и ещё лучше. Давайте создадим вспомогательный тип данных, который определяет точку в двумерном пространстве. Затем используем его для того, чтобы сделать наши фигуры более понятными:
>data Point = Point Float Float deriving (Show)
>data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
Обратите внимание, что при определении точки мы использовали одинаковые имена для конструктора типа и для конструктора данных. В этом нет какого-то особого смысла, но если у типа данных только один конструктор, как правило, он носит то же имя, что и тип. Итак, теперь у конструктора >Circle
два поля: первое имеет тип >Point
, второе – >Float
. Так легче разобраться, что есть что. То же верно и для прямоугольника. Теперь, после всех изменений, мы должны исправить функцию >area
:
>area :: Shape –> Float
>area (Circle _ r) = pi * r 2
>area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 – x1) * (abs $ y2 – y1)