относится к этой функции. Так что пропуск скобок экономит на записи. Конечно, ничто не мешает использовать скобки, если это вам больше нравится.
Тем не менее есть случаи, когда использование такой нотации оправдано. Я думаю, что функция >flip
будет лучше читаться, если мы объявим её так:
>flip' :: (a –> b –> c) –> b –> a –> c
>flip' f = \x y –> f y x
Несмотря на то что эта запись равнозначна >flip' f x y = f y x
, мы даём понять, что данная функция чаще всего используется для создания новых функций. Самый распространённый сценарий использования >flip
– вызов её с некоторой функцией и передача результирующей функции в >map
или >zipWith
:
>ghci> zipWith (flip (++)) ["люблю тебя", "любишь меня"] ["я ", "ты "]
>["я люблю тебя","ты любишь меня"]
>ghci> map (flip subtract 20) [1,2,3,4]
>[19,18,17,16]
Итак, используйте лямбда-выражения таким образом, когда хотите явно показать, что ваша функция должна быть частично применена и передана далее как параметр.
Когда мы разбирались с рекурсией, то во всех функциях для работы со списками наблюдали одну и ту же картину. Базовым случаем, как правило, был пустой список. Мы пользовались образцом >(x:xs)
и затем делали что-либо с «головой» и «хвостом» списка. Как выясняется, это очень распространённый шаблон. Были придуманы несколько полезных функций для его инкапсуляции. Такие функции называются свёртками (folds). Свёртки позволяют свести структуру данных (например, список) к одному значению.
Функция свёртки принимает бинарную функцию, начальное значение (мне нравится называть его «аккумулятором») и список. Бинарная функция принимает два параметра. Она вызывается с аккумулятором и первым (или последним) элементом из списка и вычисляет новое значение аккумулятора. Затем функция вызывается снова, с новым значением аккумулятора и следующим элементом из списка, и т. д. То, что остаётся в качестве значения аккумулятора после прохода по всему списку, и есть результат свёртки.
Для начала рассмотрим функцию >foldl
– свёртка слева. Она сворачивает список, начиная с левой стороны. Бинарная функция применяется для начального значения и первого элемента списка, затем для вновь вычисленного аккумулятора и второго элемента списка и т. д.
Снова реализуем функцию >sum
, но на этот раз будем пользоваться свёрткой вместо явной рекурсии.
>sum' :: (Num a) => [a] –> a
>sum' xs = foldl (\acc x –> acc + x) 0 xs
Проверка – раз, два, три!
>ghci> sum' [3,5,2,1]
>11
Давайте посмотрим более внимательно, как работает функция >foldl
. Бинарная функция – это лямбда-выражение