Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Несколько заключительных слов о классах типовСодержание книги
Поиск на нашем сайте Поскольку класс типа определяет абстрактный интерфейс, один и тот же тип данных может иметь экземпляры для различных клас- сов, а для одного и того же класса могут быть определены экзем- пляры различных типов. Например, тип Char имеет экземпляры для многих классов, два из которых – Eq и Ord, поскольку мы можем сравнивать символы на равенство и располагать их в алфавитном порядке. Иногда для типа данных должен быть определён экземпляр не- которого класса для того, чтобы имелась возможность определить для него экземпляр другого класса. Например, для определения эк- земпляра класса Ord необходимо предварительно иметь экземпляр класса Eq. Другими словами, наличие экземпляра класса Eq является предварительным (необходимым) условием для определения экземпля- ра класса Ord. Если поразмыслить, это вполне логично: раз уж до- пускается расположение неких значений в определённом порядке, то должна быть предусмотрена и возможность проверить их на ра- венство.
СИНТАКСИС ФУНКЦИЙ
Сопоставление с образцом
таемый. Вы можете задавать образцы для любого типа данных – чи- сел, символов, списков, кортежей и т. д. Давайте создадим простую функцию, которая проверяет, является ли её параметр числом семь. lucky:: Int -> String lucky 7 = "СЧАСТЛИВОЕ ЧИСЛО 7!"
lucky x = "Прости, друг, повезёт в другой раз!"
Когда вы вызываете функцию lucky, производится проверка па- раметра на совпадение с заданными образцами в том порядке, в ка- ком они были заданы. Когда проверка даст положительный резуль- тат, используется соответствующее тело функции. Единственный случай, когда число, переданное функции, удовлетворяет первому образцу, – когда оно равно семи. В противном случае проводится проверка на совпадение со следующим образцом. Следующий об- разец может быть успешно сопоставлен с любым числом; также он привязывает переданное число к переменной x. Если в образце вместо реального значения (например, 7) пишут идентификатор, начинающийся со строчной буквы (например, x, y или myNumber), то этот образец будет сопоставлен любому передан- ному значению. Обратиться к сопоставленному значению в теле функции можно будет посредством введённого идентификатора. Эта функция может быть реализована с использованием клю- чевого слова if. Ну а если нам потребуется написать функцию, ко- торая называет цифры от 1 до 5 и выводит "Это число не в пределах от 1 до 5" для других чисел? Без сопоставления с образцом нам бы пришлось создать очень запутанное дерево условных выражений if – then – else. А вот что получится, если использовать сопостав-
ление: sayMe:: Int -> String sayMe 1 = "Один!" sayMe 2 = "Два!" sayMe 3 = "Три!" sayMe 4 = "Четыре!" sayMe 5 = "Пять!"
sayMe x = "Это число не в пределах от 1 до 5" Заметьте, что если бы мы переместили последнюю строку опре- деления функции (образец в которой соответствует любому вводу) вверх, то функция всегда выводила бы "Это число не в пределах от 1 до 5", потому что невозможно было бы пройти дальше и провести проверку на совпадение с другими образцами. Помните реализованную нами функцию факториала? Мы оп- ределили факториал числа n как произведение чисел [1..n]. Мы можем определить данную функцию рекурсивно, точно так же, как факториал определяется в математике. Начнём с того, что объявим факториал нуля равным единице.
Затем определим факториал любого положительного числа как данное число, умноженное на факториал предыдущего числа. Вот как это будет выглядеть в терминах языка Haskell. factorial:: Integer -> Integer factorial 0 = 1
factorial n = n * factorial (n – 1) Мы в первый раз задали функцию рекурсивно. Рекурсия очень важна в языке Haskell, и подробнее она будет рассмотрена позже.
Сопоставление с образцом может завершиться неудачей, если мы зададим функцию следующим образом: charName:: Char –> String charName 'а' = "Артём" charName 'б' = "Борис" charName 'в' = "Виктор"
а затем попытаемся вызвать её с параметром, которого не ожидали. Произойдёт следующее: ghci> charName 'а' "Артём" ghci> charName 'в' "Виктор" ghci> charName 'м'
"*** Exception: Non-exhaustive patterns in function charName Это жалоба на то, что наши образцы не покрывают всех возмож- ных случаев (недоопределены) – и, воистину, так оно и есть! Когда мы определяем функцию, мы должны всегда включать образец, кото- рый можно сопоставить с любым входным значением, для того что- бы наша программа не закрывалась с сообщением об ошибке, если функция получит какие-то непредвиденные входные данные.
Сопоставление с парами Сопоставление с образцом может быть использовано и для корте- жей. Что если мы хотим создать функцию, которая принимает два двумерных вектора (представленных в форме пары) и складывает их? Чтобы сложить два вектора, нужно сложить их соответствую- щие координаты. Вот как мы написали бы такую функцию, если б не знали о сопоставлении с образцом:
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 Символ _ имеет то же значение, что и в генераторах списков. Он означает, что нам не интересно значение на этом месте, так что мы просто пишем _.
|
|||||||||||||||||||||||||||||||||||||||||
|
Последнее изменение этой страницы: 2017-02-17; просмотров: 262; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.216.236 (0.009 с.) |