Можно было бы написать конструкцию if
в одну строку, но я считаю, что это не так «читабельно». Ещё одна особенность условной конструкции в языке Haskell состоит в том, что она является выражением. Выражение – это код, возвращающий значение. 5
– это выражение, потому что возвращает 5; 4 + 8
– выражение, x + y
– тоже выражение, потому что оно возвращает сумму x и y.
Поскольку ветвь else
обязательна, конструкция if
всегда что-нибудь вернёт, ибо является выражением. Если бы мы хотели добавить единицу к любому значению, получившемуся в результате выполнения нашей предыдущей функции, то могли бы написать её тело вот так:
doubleSmallNumber' x = (if x > 100 then x else x*2) + 1
Если опустить скобки, то единица будет добавляться только при условии, что x
не больше 100. Обратите внимание на символ апострофа ('
) в конце имени функции. Он не имеет специального значения в языке Haskell. Это допустимый символ для использования в имени функции.
Обычно мы используем символ прямого апострофа '
для обозначения строгой (не ленивой) версии функции либо слегка модифицированной версии функции или переменной. Поскольку апостроф – допустимый символ в именах функций, мы можем определять такие функции:
conanO'Brien = "Это я, Конан О'Брайен!"
Здесь следует обратить внимание на две важные особенности. Во-первых, в названии функции мы не пишем имя conan
с прописной буквы. Дело в том, что наименования функций не могут начинаться с прописной буквы – чуть позже мы разберёмся, почему. Во-вторых, данная функция не принимает никаких пара метров.
Когда функция не принимает аргументов, говорят, что это константная функция. Поскольку мы не можем изменить содержание имён (и функций) после того, как их определили, идентификатор conanO'Brien
и строка "Это я, Конан О'Брайен!"
могут использоваться взаимозаменяемо.
Списки
Как и списки покупок в реальном мире, списки в языке Haskell очень полезны. В данном разделе мы рассмотрим основы работы со списками, генераторами списков и строками (которые также являются списками).
Списки в языке Haskell являются гомогенными структурами данных; это означает, что в них можно хранить элементы только одного типа. Можно иметь список целых или список символов, но нельзя получить список с целыми числами и символами одновременно.
Списки заключаются в квадратные скобки, а элементы разделяются запятыми:
ghci> let lostNumbers = [4,8,15,16,23,42]
ghci> lostNumbers
[4,8,15,16,23,42]
ПРИМЕЧАНИЕ. Можно использовать ключевое слово let
, чтобы определить имя прямо в GHCi. Например, выполнение let a = 1
из GHCi – эквивалент указания a = 1
в скрипте с последующей загрузкой.
Конкатенация
Объединение двух списков – стандартная задача. Она выполняется с помощью оператора ++
[5].
ghci> [1,2,3,4] ++ [9,10,11,12] [1,2,3,4,9,10,11,12]
ghci> "привет" ++ " " ++ "мир"
"привет мир"
ghci> ['в','о'] ++ ['-'] ++ ['о','т']
"во-от"
ПРИМЕЧАНИЕ. Строки в языке Haskell являются просто списками символов. Например, строка привет
– это то же самое, что и список ['п','р','и','в','е','т']
. Благодаря этому для работы со строками можно использовать функции обработки символов, что очень удобно.
Будьте осторожны при использовании оператора ++
с длинными строками. Если вы объединяете два списка (даже если в конец первого из них дописывается второй, состоящий из одного элемента, например [1,2,3] ++ [4]
), то язык Haskell должен обойти весь список с левой стороны от ++
. Это не проблема, когда обрабатываются небольшие списки, но добавление к списку из 50 000 000 элементов займёт много времени. А вот если вы добавите что-нибудь в начало списка с помощью оператора :
(также называемого «cons»), долго ждать не придётся.
ghci> 'В':"ОТ КОШКА"
"ВОТ КОШКА"
ghci> 5:[1,2,3,4,5]
[5,1,2,3,4,5]
Обратите внимание, что оператор :
принимает число и список чисел или символ и список символов, в то время как ++
принимает два списка. Даже если вы добавляете один элемент в конец списка с помощью оператора ++
, следует заключить этот элемент в квадратные скобки, чтобы он стал списком:
ghci> [1,2,3,4] ++ [5]
5
Следует отметить, что +
, *
, >>=
и т. д. –