×
Traktatov.net » Изучай Haskell во имя добра! » Читать онлайн
Страница 25 из 245 Настройки

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

>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) используется очень часто, особенно с рекурсивными функциями. Образцы, в определении которых присутствует >:, могут быть использованы только для списков длиной не менее единицы.

Если вы, скажем, хотите связать первые три элемента с переменными, а оставшиеся элементы списка – с другой переменной, то можете использовать что-то наподобие >(x:y:z:zs). Образец сработает только для списков, содержащих не менее трёх элементов.

Теперь, когда мы знаем, как использовать сопоставление с образцом для списков, давайте создадим собственную реализацию функции >head:

>head' :: [a] –> a

>head' [] = error "Нельзя вызывать head на пустом списке, тупица!"

>head' (x:_) = x

Проверим, работает ли это…

>ghci> head' [4,5,6]

>4

>ghci> head' "Привет"

>H'

Отлично! Заметьте, что если вы хотите выполнить привязку к нескольким переменным (даже если одна из них обозначена всего лишь символом >_ и на самом деле ни с чем не связывается), вам необходимо заключить их в круглые скобки. Также обратите внимание на использование функции >error. Она принимает строковый параметр и генерирует ошибку времени исполнения, используя этот параметр для сообщения о причине ошибки.