haskell-notes

лендаря: то что стоит за – является комментарием и игнорируется при выполнении программы:

14 | Глава 1: Основы

— Дата

data Date = Date Year Month Day

— Год

data Year

= Year Int

— Int это целые числа

— Месяц

data Month

= January

| February

| March

| April

| May

| June

| July

| August

| September

| October

| November | December

data Day = Day Int

— Неделя

data Week

= Monday

| Tuesday

| Wednesday

| Thursday

| Friday

| Saturday

| Sunday

— Время

data Time = Time Hour Minute Second

data Hour

= Hour

Int

— Час

data Minute = Minute Int

— Минута

data Second = Second Int

— Секунда

Одной из основных целей разработчиков Haskell была ясность. Они стремились создать язык, предложе-

ния которого будут простыми и понятными, близкий к языку спецификаций.

С символом | мы уже познакомились, он указывает на альтернативы, объединение пишется через пробел.

Так, фраза

data Time = Time Hour Minute Second

означает, что тип Time – это значение с меткой Time, которое состоит из значений типов “час”, “время” и

“секунда”, и больше ничего. Метку принято называть конструктором.

Фраза

data Year = Year Int

означает, что тип Year – это значение с конструктором Year, которое состоит из одного значения типа

Int. Конструктор обычно идёт первым, а за ним через пробел следуют другие типы. Конструктор может быть

и самостоятельным значением, как в случае True или January.

Типы делят выполнение программы на две стадии: компиляцию (compile-time) и вычисление (run-time). На

этапе компиляции происходит проверка типов. Программа, которая не прошла проверку типов, считается

бессмысленной и не вычисляется. Приложение, которое выполняет компиляцию, называют компилятором

(compiler), а то приложение, которое проводит вычисление, называют вычислителем (run-time system).

Типами мы определяем основные понятия в том явлении, которое мы хотим описать, а также осмыслен-

ные способы их комбинирования. Мы говорим, как из простейших терминов получаются составные. Если мы

попытаемся построить бессмысленное предложение, компилятор языка автоматически найдёт такое предло-

жение и сообщит нам об этом. Этот процесс заключается в проверке типов, к примеру если у нас есть функция

сложения чисел, и мы попытаемся передать в неё строку или список, компилятор заметит это и скажет нам

об этом перед тем как программа начнёт выполнятся. И важно то, что это произойдёт очень быстро. Если мы

случайно ошиблись в выражении, которое будет вычислено через час, нам не нужно ждать пока вычислитель

дойдёт до ошибки, мы узнаем об этом, не успев моргнуть, после запуска программы.

Итак, если мы попробуем составить время из месяцев и логических значений:

Time January True 23

компилятор предупредит нас об ошибке. Наверное, вы думаете, что приведенный пример надуман, ведь

кому захочется составлять время из логических значений? Но когда вы пишете программу, часто процесс

работы складывается так: вы думаете над одним, пишете другое, а также планируете вернуться к третьему.

И знание того, что есть надежный компилятор, который не пропустит глупых ошибок, освобождает руки, вы

можете не заботиться о таких пустяках, как правильное построение предложения.

Отметим, что такой подход с разделением вычисления на две стадии и проверкой типов называется

статической типизацией. Есть и другие языки, в них типы лишь подразумеваются и программа сразу начинает

Типы | 15

вычисляться, если есть какие-то несоответствия, об ошибке программисту сообщит вычислитель, причём

только тогда, когда вычисление дойдёт до ошибки. Такой подход называют динамической типизацией.

Типы требуют серьёзных размышлений на начальном этапе, этапе определения базовых терминов и спо-

собов их комбинирования. Не упускаем ли мы что-то важное из виду, или, может быть, типы имеют слишком

общий характер и допускают ненужные нам предложения? Приходится задумываться. Но если типы подо-

браны удачно, они сами начинают подсказывать, как строить программу.

1.3 Значения

Итак, мы определили типами базовые понятия и способы комбинирования. Обычно это небольшой набор

слов. Например в логических выражениях всего лишь два слова. Можем ли мы на что либо рассчитывать с

таким словарным запасом? Оказывается, что да. Здесь на помощь приходят синонимы. Сейчас у нас в активе

лишь два слова:

data Bool = True | False

И мы можем определить два синонима:

true :: Bool

true = True

false :: Bool

false = False

В Haskell синонимы пишутся с маленькой буквы. Синоним определяется через знак =. Обратите внимание

на то, что это не процесс вычисления значения. Мы всего лишь объявляем новое имя для комбинации слов.

Теперь мы имеем целых четыре слова! Тем не менее, ушли мы не далеко, и два новых слова, в сущности,

не делают язык выразительнее. Такие синонимы называют константами. Это значит, что одним словом мы

будем обозначать некоторую комбинацию других слов. В данном случае комбинации очень простые.

Но наши синонимы могут определять одни слова через другие. Синонимы могут принимать параметры.

Параметры пишутся через пробел между новым именем и знаком равно:

not :: Bool -> Bool

not True

= False

not False = True

Мы определили новое имя not с типом Bool -> Bool. Оно определяется двумя уравнениями (clause). Слева

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162