Изучай Haskell во имя добра! (Липовача) - страница 81

, >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)