Изучай Haskell во имя добра! (Липовача) - страница 55

Если вы обратитесь к примеру, приведённому в предыдущем разделе, то увидите, что мы создали функцию >isLong в секции >where функции >numLongChains только для того, чтобы передать её в фильтр. Вместо этого можно использовать анонимную функцию:

>numLongChains :: Int

>numLongChains = length (filter (\xs –> length xs > 15) (map chain [1..100]))



Анонимные функции являются выражениями, поэтому мы можем использовать их таким способом, как в примере. Выражение >(\xs –> length xs > 15) возвращает функцию, которая говорит нам, больше ли >15 длина переданного списка.

Те, кто не очень хорошо понимает, как работает каррирование и частичное применение функций, часто используют анонимные функции там, где не следует. Например, выражения >map (+3) [1,6,3,2] и >map (\x –> x + 3) [1,6,3,2] эквивалентны, так как >(+3) и >(\x –> x + 3) – это функции, которые добавляют тройку к аргументу. Излишне говорить, что использование анонимной функции в этом случае неоправданно, так как частичное применение значительно легче читается.

Как и обычные функции, лямбда-выражения могут принимать произвольное количество параметров:

>ghci> zipWith (\a b –> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]

>[153.0,61.5,31.0,15.75,6.6]

По аналогии с обычными функциями, можно выполнять сопоставление с образцом в лямбда-выражениях. Единственное отличие в том, что нельзя определить несколько образцов для одного параметра – например, записать для одного параметра образцы >[] и >(x: xs) и рассчитывать, что выполнение перейдёт к образцу >(x:xs) в случае неудачи с >[]. Если сопоставление с образцом в анонимной функции заканчивается неудачей, происходит ошибка времени выполнения, так что поосторожнее с этим!

>ghci> map (\(a,b) –> a + b) [(1,2),(3,5),(6,3),(2,6),(2,5)]

>[3,8,9,8,7]

Обычно анонимные функции заключаются в круглые скобки, если только мы не хотим, чтобы лямбда-выражение заняло всю строку. Интересная деталь: поскольку все функции каррированы по умолчанию, допустимы две эквивалентные записи.

>addThree :: Int -> Int -> Int -> Int

>addThree x y z = x + y + z


>addThree' :: Int -> Int -> Int -> Int

>addThree' = \x -> \y -> \z -> x + y + z

Если мы объявим функцию подобным образом, то станет понятно, почему декларация типа функции представлена именно в таком виде. И в декларации типа, и в теле функции имеются три символа >–>. Конечно же, первый способ объявления функций значительно легче читается; второй – это всего лишь очередная возможность продемонстрировать каррирование.

ПРИМЕЧАНИЕ. Обратите внимание на то, что во втором примере анонимные функции не заключены в скобки. Когда вы пишете анонимную функцию без скобок, предполагается, что вся часть после символов