Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Функции в качестве аппликативных функторовСодержание книги
Поиск на нашем сайте
Ещё одним экземпляром класса Applicative является тип (–>) r, или функции. Мы нечасто используем функции в аппликативном стиле, но концепция, тем не менее, действительно интересна, поэтому да- вайте взглянем, как реализован экземпляр функции1. instance Applicative ((–>) r) where pure x = (\_ –> x) f <*> g = \x –> f x (g x) Когда мы оборачиваем значение в аппликативное значение с помощью функции pure, результат, который оно возвращает, дол- жен быть этим значением. Минимальный контекст по умолчанию по-прежнему возвращает это значение в качестве результата. Вот почему в реализации экземпляра функция pure принимает значение 1 Читателей, знакомых с комбинаторной логикой, такое определение экземпляра класса Applicative для функционального типа смутить не должно – методы опре- деляют комбинаторы K и S соответственно. – Прим. ред. и создаёт функцию, которая игнорирует передаваемый ей пара- метр и всегда возвращает это значение. Тип функции pure для эк- земпляра типа (–>) r выглядит как pure:: a –> (r –> a). ghci> (pure 3) "ля" 3 Из-за каррирования применение функции левоассоциативно, так что мы можем опустить скобки: ghci> pure 3 "ля" 3 Реализация экземпляра <*> немного загадочна, поэтому давайте посмотрим, как использовать функции в качестве аппликативных функторов в аппликативном стиле: ghci>:t (+) <$> (+3) <*> (*100) (+) <$> (+3) <*> (*100):: (Num a) => a –> a ghci> (+) <$> (+3) <*> (*100) $ 5 508 Вызов оператора <*> с двумя аппликативными значениями возвращает аппликативное значение, поэтому если мы вызываем его с двумя функциями, то получаем функцию. Что же здесь проис- ходит? Когда мы выполняем (+) <$> (+3) <*> (*100), мы со- здаём функцию, которая при- менит оператор + к резуль- татам выполнения функций (+3) и (*100) и вернёт это зна- чение. При вызове выраже- ния (+) <$> (+3) <*> (*100) $ 5 функции (+3) и (*100) снача- ла применяются к значению 5, что в результате даёт 8 и 500; затем оператор + вызывается со значениями 8 и 500, что в результате даёт 508. Следующий код аналогичен: ghci> (\x y z –> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5 [8.0,10.0,2.5]
Мы создаём функцию, которая вызоветфункцию \xy z –> [x, y, z] с окончательными результатами выполнения, возвращёнными функциями (+3), (*2) и (/2). Значение 5 передаётся каждой из трёх функций, а затем с этими результатами вызывается анонимная фун- кция \x y z –> [x, y, z]. ПРИМЕЧАНИЕ. Не так уж важно, поняли ли вы, как работает эк- земпляр типа (–>) r для класса Applicative, так что не отчаивай- тесь, если вам это пока не ясно. Поработайте с аппликативным стилем и функциями, чтобы получить некоторое представление о том, как использовать функции в качестве аппликативных функ- торов. Застёгиваемые списки Оказывается, есть и другие способы для списков быть аппликатив- ными функторами. Один способ мы уже рассмотрели: вызов опера- тора <*> со списком функций и списком значений, который возвра- щает список всех возможных комбинаций применения функций из левого списка к значениям в списке справа. Например, если мы выполним [(+3),(*2)] <*> [1,2], то фун- кция (+3) будет применена и к 1, и к 2; функция (*2) также будет применена и к 1, и к 2, а результатом станет список из четырёх эле- ментов: [4,5,2,4]. Однако [(+3),(*2)] <*> [1,2] могла бы работать и таким образом, чтобы первая функция в списке слева была при- менена к первому значению в списке справа, вторая была бы при- менена ко второму значению и т. д. Это вернуло бы список с двумя значениями: [4,4]. Вы могли бы представить его как [1 + 3, 2 * 2]. Экземпляром класса Applicative, с которым мы ещё не встре- чались, является тип ZipList, и находится он в модуле Control. Applicative. Поскольку один тип не может иметь два экземпляра для одного и того же класса типов, был введён тип ZipList a, в котором имеется один конструктор (ZipList) с единственным полем (список). Вот так определяется его экземпляр: instance Applicative ZipList where pure x = ZipList (repeat x) ZipList fs <*> ZipList xs = ZipList (zipWith (\f x –> f x) fs xs)
Оператор <*> применяет первую функцию к первому значению, вторую функцию – ко второму значению, и т. д. Это делается с помо- щью выражения zipWith (\f x –> f x) fs xs. Ввиду особенностей рабо- ты функции zipWith окончательный список будет той же длины, что и более короткий список из двух. Функция pure здесь также интересна. Она берёт значение и по- мещает его в список, в котором это значение просто повторяется бесконечно. Выражение pure "ха-ха" вернёт ZipList (["ха-ха","ха- ха","ха-ха"... Это могло бы сбить с толку, поскольку вы узнали, что функция pure должна помещать значение в минимальный контекст, который по-прежнему возвращает данное значение. И вы могли бы подумать, что бесконечный список чего-либо едва ли является минимальным. Но это имеет смысл при использовании застёгива- емых списков, так как значение должно производиться в каждой позиции. Это также удовлетворяет закону о том, что выражение pure f <*> xs должно быть эквивалентно выражению fmap f xs. Если бы вызов выражения pure 3 просто вернул ZipList [3], вызов pure ( *2) <*> ZipList [1,5,10] дал бы в результате ZipList [2], потому что длина результирующего списка из двух застёгнутых списков равна длине более короткого списка из двух. Если мы застегнем конеч- ный список с бесконечным, длина результирующего списка всегда будет равна длине конечного списка. Так как же застёгиваемые списки работают в аппликативном стиле? Давайте посмотрим. Ладно, тип ZipList a не имеет экземпляра класса Show, поэто- му мы должны использовать функцию getZipList для извлечения обычного списка из застёгиваемого: ghci> getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [100,100,100] [101,102,103] ghci> getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [100,100..] [101,102,103] ghci> getZipList $ max <$> ZipList [1,2,3,4,5,3] <*> ZipList [5,3,1,2] [5,3,3,4] ghci> getZipList $ (,,) <$> ZipList "пар" <*> ZipList "ток" <*> ZipList "вид" [('п','т','в'),('а','о','и'),('р',кt','д')]
ПРИМЕЧАНИЕ. Функция (,,) – это то же самое, что и анонимная функция \x y z –> (x,y,z). В свою очередь, функция (,) – то же самое, что и \x y –> (x,y). Помимо функции zipWith в стандартной библиотеке есть такие функции, как zipWith3, zipWith4, вплоть до 7. Функция zipWith берёт функцию, которая принимает два параметра, и застёгивает с её по- мощью два списка. Функция zipWith3 берёт функцию, которая при- нимает три параметра, и застёгивает с её помощью три списка, и т. д. При использовании застёгиваемых списков в аппликативном стиле нам не нужно иметь отдельную функцию застёгивания для каждого числа списков, которые мы хотим застегнуть друг с другом. Мы прос- то используем аппликативный стиль для застёгивания произвольно- го количества списков при помощи функции, и это очень удобно.
Аппликативные законы Как и в отношении обычных функторов, применительно к аппли- кативным функторам действует несколько законов. Самый главный состоит в том, чтобы выполнялось тождество pure f <*> x = fmap f x. В качестве упражнения можете доказать выполнение этого закона для некоторых аппликативных функторов из этой главы. Ниже пе- речислены другие аппликативные законы: ® pure id <*> v = v ® pure (.) <*> u <*> v <*> w = u <*> (v <*> w) ® pure f <*> pure x = pure (f x) ® u <*> pure y = pure ($ y) <*> u Мы не будем рассматривать их подробно, потому что это заняло бы много страниц и было бы несколько скучно. Если вам интерес- но, вы можете познакомиться с этими законами поближе и посмот- реть, выполняются ли они для некоторых экземпляров.
|
|||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2017-02-17; просмотров: 212; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 13.59.36.4 (0.007 с.) |