52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 67

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 67

Смотрите мы составили предикат сразу в аргументе функции filter. Выражение (\x -> x > 2 && x <

10 && even x) является обычным значением.

Возможно у вас появился вопрос, где аргумент функции? Где тот список по которому мы проводим филь-

трацию. Ответ на этот вопрос кроется в частичном применении. Давайте вычислим по правилу применения

тип функции filter:

f :: (a -> Bool) -> [a] -> [a],

x :: (Int -> Bool)

------------------------------------------------------

(f x) :: [Int] -> [Int]

После применения параметр a связывается с типом Int, поскольку при применении происходит сопостав-

ление более общего предиката a -> Bool из функции filter с тем, который мы передали первым аргументом

Int -> Bool. После этого мы получаем тип (f x) :: [Int] -> [Int] это как раз тип функции, которая прини-

мает список целых чисел и возвращает список целых чисел. Частичное применение позволяет нам не писать

в таких выражениях:

f xs = filter p xs

where p x = ...

последний аргумент xs.

К примеру вместо

Определение функций | 65

add a b = (+) a b

мы можем просто написать:

add = (+)

Такой стиль определения функций называют бесточечным (point-free).

Давайте выразим функцию filter с помощью лямбда-функций:

filter :: (a -> Bool) -> ([a] -> [a])

filter = \p -> \xs -> case xs of

[]

-> []

(x:xs) -> let rest = filter p xs

in

if

p x

then x : rest

else rest

Мы определили функцию filter пользуясь только элементами композиционного стиля. Обратите внима-

ние на скобки в объявлении типа функции. Я хотел напомнить вам о том, что все функции в Haskell являются

функциями одного аргумента. Это определение функции filter как нельзя лучше подчёркивает этот факт.

Мы говорим, что функция filter является функцией одного аргумента p в выражении \p -> , которая возвра-

щает также функцию одного аргумента. Мы выписываем это в явном виде в выражении \xs -> . Далее идёт

выражение, которое содержит определение функции.

Отметим, что лямбда функции могут принимать несколько аргументов, в предыдущем определении мы

могли бы написать:

filter :: (a -> Bool) -> ([a] -> [a])

filter = \p xs -> case xs of

...

но это лишь синтаксический сахар, который разворачивается в предыдущую запись.

Для тренировки определим несколько стандартных функций для работы с кортежами с помощью лямбда-

функций (все они определены в Prelude):

fst :: (a, b) -> a

fst = \(a, _) -> a