Аппликативные функции, отличные от монадов и ZipList?

Двумя хорошо известными примерами аппликаций являются монады и ziplists. Есть ли другие примеры?

Ответ 1

Из Время летает, как аппликативный функтор, Конор Макбрайд:

Структурные менты заметят, что De - это еще один пример аппликативного функтора, который не является монадом - объединение принесет вещи из далекого будущего в ближайшем будущем, и это было бы лучше не возможно. Однако, когда аппликативные функторы вообще тянут через проходящие функции (контейнеры с конечным числом элементов), De проталкивает все контейнеры. Так что это немного особенное. Интересно, что это такое.

и

Функтор De представляет собой фиксированную задержку, а не произвольную. Im делит время на дискретные срезы. De x - это тип x, который должен появиться на следующем фрагменте. Таким образом, De (De x) является типом x, обусловленным двумя часами, и вы не можете заставить его появляться раньше!

Прочитайте весь пост. Чтобы ответить на ближайший вопрос, заключение авторов

Не смотрите!

ОК, это реализация. Его кон.

newtype De x = De x deriving Show -- ssh, don't tell!

instance Functor De where
  fmap f (De x) = De (f x)

instance Applicative De where
  pure = De
  De f <*> De s = De (f s)

fix :: (De x -> x) -> x
fix f = f (De (fix f))

Ответ 2

Недавно я определил аппликативный экземпляр для newtype поверх (,,,), "quad". (Стандартная библиотека определяет экземпляр для (,), но не (,,,). Это нормально, поскольку стандартная реализация имеет разную семантику, чем то, что было после.)

Фон - это; Я разбираю некоторые старые данные, а формат даты в данных неоднозначен. Каждая дата в данных может быть проанализирована на четыре возможности, сохраненные в квадранте. Затем я хочу проверить каждую дату в квадрате, чтобы исключить семантически недействительные даты. (Нет месяцев с 32 днями, нет месяца 34, нет пятого квартала и т.д.). Наконец, я хочу взять каждую дату в наборе данных и уменьшить весь набор до квадрата, представляющего, какие форматы даты действительны для всего набора. Затем я выбираю лучший формат из этих параметров и предполагаю, что формат даты набора данных.

Вся эта операция очень легко выразить как прикладные операции на квадрантной структуре.

Здесь основная форма кода:

Мой новый тип:

newtype DQ a = DQ (a, a, a, a) -- date quad
             deriving ...

instance Functor DQ where
   g `fmap` f = pure g <*> f

instance Applicative DQ where
   pure x  = DQ (x, x, x, x)
   DQ (g, h, i, j) <*> DQ (a, b, c, d) = DQ (g a, h b, i c, j d)

Некоторые предпосылки "чистые" функции:

parseDateInt :: Int -> DQ Date
validateDate :: Date -> Bool
extractBestDate :: DQ Date -> DQ Bool -> Date

Итак, как только у нас есть квадрат синтаксических дат (от parseDateInt), нам нужно проверить их:

validateDates :: DQ Date -> DQ Bool
validateDates = (validateDate <$>)

(Это до сих пор только Functor, но вы также можете написать (pure validateDate <*>).

Также стоит отметить симметрию между проверкой одного элемент и проверка каждого элемента набора - чтобы его проверить, вы можете написать validateDate $ date; для проверки набора вы пишете validateDate <$> dates. Вот почему fmap записывается как <$>, это приложение функции к функтору.)

После этого нужно выполнить набор действительных разбора и свернуть это в конечный результат:

intuitDateType :: [DQ Bool] -> DQ Bool
intuitDateType dates = foldl1 (liftA2 (&&)) dates

Итак, теперь вы можете перейти от [Int] в файл данных к DQ Bool представляющие возможные допустимые представления даты для набора данных. (И оттуда свяжите каждую точку данных с реальным объектом даты, а не flaky Int, который был поставлен.)

Так или иначе, этот пост получил немного длинный, но идея в том, что Аппликационный пример позволил мне решить мою проблему примерно в 3 строках кода. Мой проблемный домен неоднократно применял функции к данным в контейнер, что и делает прикладной функтор. Для этих данных нет операции join, поэтому экземпляр Monad не имеет большого смысла.

Ответ 3

Конал Эллиотт пишет о сигнальных процессорах и о том, как они применяются. Они похожи на ZipList в природе, где каждая соответствующая пара элементов в двух "контейнерах" объединяется.

Я много использовал эту концепцию в незавершенной, но милой игре, которую я сделал (cabal install DefendTheKing, чтобы проверить это).

Фрагмент кода/пример использования аппликативного стиля:

draw font
<$> lstP gABoard
<*> lstP gASelection
<*> mouseMotion
<*> lstP gASide
<*> lstP gAGameIteration

Ответ 4

Formlets являются абстракцией над формами HTML, описанными в терминах составления аппликаций. Аппликация формлета является результатом составления имени, генерирующего аппликативный (для генерации имен элементов формы), приложения для создания XML-кода (для генерации HTML) и применения среды (для подачи представленных значений формы).

Формлеты могут быть расширены за счет добавления дополнительных аппликаций, например для реализации проверки.

Купер, Вадлер и др. показывают в работах, что формылеты не могут быть представлены как монады.

В Haskell реализованы Formlets, вот пакет.

Ответ 5

Swierstra и Duponcheel определили эффективный стиль парсера, этот синтаксический анализатор был в значительной степени ранним платиновым ребенком для Arrows, но ему ничего не нужно от Arrow, которое он не может получить от Applicative. Тем не менее, в то время не было приложено применение.

Эффективно он вычисляет множества "FIRST" для парсера LL (1) и использует это для более интеллектуального выбора ветки. Тем не менее, вы не можете вычислять эти наборы, когда вы работаете монадически.

Это, пожалуй, не очень правдоподобный пример, потому что парсер Swierstra/Duponcheel допускает смешивание статических и динамических парсеров, и только статический парсер ограничивается возможностью применения.

С наблюдаемым разделением вы можете нести свой парсерный дизайн дальше, а также вычислить множества "FOLLOW" (пока вы не станете строить бесконечную контекстную грамматику). Это дает хорошие асимптотические гарантии для разбора контекстных свободных грамматик, которые недоступны вам при разборе с использованием монадических (контекстно-зависимых) парсеров.

Также интересным, возможно, является рассмотрение структур, для которых доступно аппликативное приложение, но не чистое. Многие comonads допускают (< * > ) -подобное определение, которое учитывает структуру comonad, но не имеют разумного определения для "чистого". Мой пакет semigroupoids и множество пакетов, которые зависят от него, исследуют эту идею дальше.

Ответ 6

Я считаю, что стрелы являются аппликативными функторами. В Control.Applicative есть тип WrapArrow.

Ответ 7

McBride и Paterson http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf показывают, что моноид можно рассматривать как прикладной функтор, но в общем случае это не монада.