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

Сопоставление с парами

Сопоставление с образцом может быть использовано и для кортежей. Что если мы хотим создать функцию, которая принимает два двумерных вектора (представленных в форме пары) и складывает их? Чтобы сложить два вектора, нужно сложить их соответствующие координаты. Вот как мы написали бы такую функцию, если б не знали о сопоставлении с образцом:

>addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)

>addVectors a b = (fst a + fst b, snd a + snd b)

Это, конечно, сработает, но есть способ лучше. Давайте исправим функцию, чтобы она использовала сопоставление с образцом:

>addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)

>addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)

Так гораздо лучше. Теперь ясно, что параметры функции являются кортежами; к тому же компонентам кортежа сразу даны имена – это повышает читабельность. Заметьте, что мы сразу написали образец, соответствующий любым значениям. Тип функции >addVectors в обоих случаях совпадает, так что мы гарантированно получим на входе две пары:

>ghci> :t addVectors

>addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)

Функции >fst и >snd извлекают компоненты пары. Но как быть с тройками? Увы, стандартных функций для этой цели не существует, однако мы можем создать свои:

>first :: (a, b, c) –> a

>first (x, _, _) = x


>second :: (a, b, c) –> b

>second (_, y, _) = y


>third :: (a, b, c) –> c

>third (_, _, z) = z

Символ >_ имеет то же значение, что и в генераторах списков. Он означает, что нам не интересно значение на этом месте, так что мы просто пишем >_.

Сопоставление со списками и генераторы списков

В генераторах списков тоже можно использовать сопоставление с образцом, например:

>ghci> let xs = [(1,3), (4,3), (2,4), (5,3), (5,6), (3,1)]

>ghci> [a+b | (a,b) <– xs]

>[4,7,6,8,11,4]

Если сопоставление с образцом закончится неудачей для одного элемента списка, просто произойдёт переход к следующему элементу.

Списки сами по себе (то есть заданные прямо в тексте образца списковые литералы) могут быть использованы при сопоставлении с образцом. Вы можете проводить сравнение с пустым списком или с любым образцом, который включает оператор >: и пустой список. Так как выражение >[1,2,3] – это просто упрощённая запись выражения >1:2:3:[], можно использовать >[1,2,3] как образец.

Образец вида >(x:xs) связывает «голову» списка с >x, а оставшуюся часть – с >xs, даже если в списке всего один элемент; в этом случае >xs – пустой список.

ПРИМЕЧАНИЕ. Образец >(x:xs) используется очень часто, особенно с рекурсивными функциями. Образцы, в определении которых присутствует