>initials firstname lastname = [f] ++ ". " ++ [l] ++ "."
> where (f:_) = firstname
> (l:_) = lastname
Можно было бы выполнять сопоставление с образцом прямо в параметрах функции (это проще и понятнее), но мы хотим показать, что это допускается сделать и в определениях после ключевого слова >where
.
Функции в блоке where
Точно так же, как мы определяли константы в секции >where
, можно определять и функции. Придерживаясь нашей темы «здорового» программирования, создадим функцию, которая принимает список из пар «вес–рост» и возвращает список из ИМТ.
>calcBmis :: [(Double, Double)] –> [Double]
>calcBmis xs = [bmi w h | (w, h) <– xs]
> where bmi weight height = weight / height 2
Видите, что происходит? Причина, по которой нам пришлось представить >bmi
в виде функции в данном примере, заключается в том, что мы не можем просто вычислить один ИМТ для параметров, переданных в функцию. Нам необходимо пройтись по всему списку и для каждой пары вычислить ИМТ.
Пусть будет let
Определения, заданные с помощью ключевого слова >let
, очень похожи на определения в секциях >where
. Ключевое слово >where
– это синтаксическая конструкция, которая позволяет вам связывать выражения с переменными в конце функции; объявленные переменные видны во всём теле функции, включая сторожевые условия. Ключевое же слово >let
позволяет связывать выражения с именами в любом месте функции; конструкции >let
сами по себе являются выражениями, но их область видимости ограничена локальным контекстом. Таким образом, определение >let
, сделанное в охранном выражении, видно только в нём самом.
Как и любые другие конструкции языка Haskell, которые используются для привязывания имён к значениям, определения >let
могут быть использованы в сопоставлении с образцом. Посмотрим на них в действии! Вот как мы могли бы определить функцию, которая вычисляет площадь поверхности цилиндра по высоте и радиусу:
>cylinder :: Double -> Double -> Double
>cylinder r h =
> let sideArea = 2 * pi * r * h
> topArea = pi * r 2
> in sideArea + 2 * topArea
Общее выражение выглядит так: >let <определения> in <выражение>
. Имена, которые вы определили в части >let
, видимы в выражении после ключевого слова >in
. Как видите, мы могли бы воспользоваться ключевым словом >where
для той же цели. Обратите внимание, что имена также выровнены по одной вертикальной позиции. Ну и какая разница между определениями в секциях >where
и >let
? Просто, похоже, в секции >let
сначала следуют определения, а затем выражение, а в секции >where
– наоборот.
На самом деле различие в том, что определения >let
сами по себе являются выражениями. Определения в секциях >where
– просто синтаксические конструкции. Если нечто является выражением, то у него есть значение. >"Фуу!"
– это выражение, и >3+5
– выражение, и даже >head [1,2,3]
. Это означает, что определение >let
можно использовать практически где угодно, например:
>ghci> 4 * (let a = 9 in a + 1) + 2
>42
Ключевое слово >let
подойдёт для определения локальных функций:
>ghci> [let square x = x * x in (square 5, square 3, square 2)]
>[(25,9,4)]
Если нам надо привязать значения к нескольким переменным в одной строке, мы не можем записать их в столбик. Поэтому мы разделяем их точкой с запятой.