внутри генератора списка, видны в функции вывода (часть до символа |) и для всех предикатов и секций, которые следуют после ключевого слова
>let
. Так что мы можем написать функцию, которая выводит только толстяков:
>calcBmis :: [(Double, Double)] -> [Double]
>calcBmis xs = [bmi | (w, h) <– xs, let bmi = w / h ^ 2, bmi > 25.0]
Использовать имя >bmi
в части >(w, h) <– xs
нельзя, потому что она расположена до ключевого слова >let
.
Часть >in
также может быть пропущена при определении функций и констант напрямую в GHCi. В этом случае имена будут видимы во время одного сеанса работы GHCi.
>ghci> let zoot x y z = x * y + z
>ghci> zoot 3 9 2
>29
>ghci> let boot x y z = x * y + z in boot 3 4 2
>14
>ghci> boot
>:1:0: Not in scope: `boot'
Поскольку в первой строке мы опустили часть >in
, GHCi знает, что в этой строке >zoot
не используется, поэтому запомнит его до конца сеанса. Однако во втором выражении >let
часть >in
присутствует, и определённая в нём функция >boot
тут же вызывается. Выражение >let
, в котором сохранена часть >in
, является выражением и представляет некоторое значение, так что GHCi именно это значение и печатает.
Выражения для выбора из вариантов
Во многих императивных языках (C, C++, Java, и т. д.) имеется оператор >case
, и если вам доводилось программировать на них, вы знаете, что это такое. Вы берёте переменную и выполняете некую часть кода для каждого значения этой переменной – ну и, возможно, используете финальное условие, которое срабатывает, если не отработали другие.
Язык Haskell позаимствовал эту концепцию и усовершенствовал её. Само имя «выражения для выбора» указывает на то, что они являются… э-э-э… выражениями, так же как >if
– >then
– >else
и >let
. Мы не только можем вычислять выражения, основываясь на возможных значениях переменной, но и производить сопоставление с образцом.
Итак, берём переменную, выполняем сопоставление с образцом, выполняем участок кода в зависимости от полученного значения… где-то мы это уже слышали!.. Ах да, сопоставление с образцом по параметрам при объявлении функции! На самом деле это всего лишь навсего облегчённая запись для выражений выбора. Эти два фрагмента кода делают одно и то же – они взаимозаменяемы:
>head' :: [a] –> a
>head' [] = error "Никаких head для пустых списков!"
>head' (x:_) = x
>head' :: [a] –> a
>head' xs =
> case xs of
> [] –> error "Никаких head для пустых списков!"
> (x:_) –> x
Как видите, синтаксис для выражений отбора довольно прост:
>case expression of
> pattern –> result
> pattern –> result
> ...
Выражения проверяются на соответствие образцам. Сопоставление с образцом работает как обычно: используется первый образец, который подошёл. Если были опробованы все образцы и ни один не подошёл, генерируется ошибка времени выполнения.