2012-04-20 6 views
27

Я читал об аппликативных функторах, особенно в функциональной жемчужине Макбрайда и Патерсона. Но я хотел бы укрепить свое понимание, выполняя некоторые упражнения. Я бы предпочел программирование, но упражнения на упражнения тоже в порядке. Какие упражнения помогут мне научиться эффективно программировать с помощью аппликативных функторов?Где найти упражнения программирования для аппликативных функторов?

Индивидуальные упражнения в порядке, как указатели на упражнения, перечисленные в другом месте.

+3

Я не могу предложить упражнения, но вы можете посмотреть на аппликативные функторы, которые не являются монадами (как представляется, главный вопрос: «зачем создавать аппликативный функтор, когда он менее мощный, чем монада?»). Применения с несколькими ошибками (в Патерсоне и Макбрайде) - это один, есть парсеры Doaitse Swierstra, анимационный один _Active_ в классной доске Andy Gill и Kevin Matledge, плюс я думаю, что Энди Гилл и его коллеги Kansas Lava основаны на аппликативном функторе. –

ответ

20

Кажется забавным опубликовать некоторые вопросы в качестве ответа. Это весело, взаимодействие между Applicative и Traversable, основано на судоку.

(1) Рассмотрим

data Triple a = Tr a a a 

Построить

instance Applicative Triple 
instance Traversable Triple 

так, что экземпляр Applicative делает "векторизации" и экземпляр Traversable работает слева направо. Не забудьте построить подходящий экземпляр Functor: убедитесь, что вы можете извлечь его из любого из Applicative или Traversable экземпляра. Вы можете найти

newtype I x = I {unI :: x} 

Полезно для последнего.

(2) Рассмотрим

newtype (:.) f g x = Comp {comp :: f (g x)} 

Показать, что

instance (Applicative f, Applicative g) => Applicative (f :. g) 
instance (Traversable f, Traversable g) => Traversable (f :. g) 

Теперь определим

type Zone = Triple :. Triple 

Пусть мы представляем Board в виде вертикальной зоны горизонтальных зон

type Board = Zone :. Zone 

Показать, как изменить его как горизонтальную зону вертикальных зон и как квадрат квадратов, используя функциональность traverse.

(3) Рассмотрим

newtype Parse x = Parser {parse :: String -> [(x, String)]} deriving Monoid 

или другую подходящую конструкцию (с учетом того, что поведение библиотеки Monoid для | Может быть | неуместно).Построить

instance Applicative Parse 
instance Alternative Parse -- just follow the `Monoid` 

и осуществлять

ch :: (Char -> Bool) -> Parse Char 

, который потребляет и поставляет характер, если оно принимается по заданному предикату.

(4) Выполнить синтаксический анализатор, который потребляет любое количество пробелов, за которым следует одна цифра (0 представляет пробелы)

square :: Parse Int 

Использование pure и traverse построить

board :: Parse (Board Int) 

(5) Рассмотрим постоянные функторы

newtype K a x = K {unK :: a} 

и constru кт

instance Monoid a => Applicative (K a) 

затем использовать traverse реализовать

crush :: (Traversable f, Monoid b) => (a -> b) -> f a -> b 

Построить newtype оберток для Bool выражения своих присоединительные и дизъюнктивных моноидных структур. Используйте crush для реализации версий any и all, которые работают для любого функтора Traversable.

(6) Реализация

duplicates :: (Traversable f, Eq a) => f a -> [a] 

вычисления список значений, которые имеют место более одного раза. (Не совсем тривиальна.) (Там это прекрасный способ сделать это с помощью дифференциального исчисления, но это другая история.)

(7) Реализовать

complete :: Board Int -> Bool 
ok :: Board Int -> Bool 

который проверить, если плата (1) полная только цифр в [1..9] и (2), лишенных дубликатов в любой строке, столбце или поле.

+0

Большие упражнения! – luqui

5

Проверьте Typeclassopedia. Он идет с хорошим объяснением с нуля и некоторыми упражнениями на этом пути.

4

Например: Applicative Functors

+0

Эта ссылка кажется мертвой, но [это страница в Internet Way Way Machine Machine] (https://web.archive.org/web/*/http://www.cis.upenn.edu/~cis194/lectures/ *): [Функторы] (https://web.archive.org/web/20130803145920/http://www.cis.upenn.edu/~cis194/lectures/09-functors.html); [Аппликативные функции] (https://web.archive.org/web/20130803134207/http://www.cis.upenn.edu/~cis194/lectures/10-applicative.html) –

12

Отличный способ на практике является использование Parsec в аппликативным, а не монадической стиле. Большинство парсеров являются чисто аппликативными, поэтому вам не нужно использовать нотацию do.

Например. для выражений:

import qualified Text.Parsec as P 
import qualified Text.Parsec.Token as P 
import Control.Applicative 

data Expr = Number Int | Plus Expr Expr 

lex = P.makeTokenParser ... -- language config 

expr = number <|> plus 
    where 
    number = Number <$> P.integer lex 
    plus = Plus <$> number <* P.symbol lex "+" <*> expr 
+0

Мне любопытно, Вы можете дать некоторые общие или, по крайней мере, разумные примеры, которые вы * не можете проанализировать с помощью аппликативного функтора, но можете с монадой? –

+7

@ Тихон Джевиль, * формально * они эквивалентны по силе, по крайней мере, над конечным алфавитом, но в виде патологического пути (оба они поддерживают бесконечные грамматики). Но хорошим примером того, где вам (разумно) нужна монада, было бы, если бы у вас был язык, который мог бы определять новые грамматические конструкции, которые следует учитывать позже в анализе.'Applicative' не может изменить свою * структуру * на основе своего * content *,' Monad' can. – luqui

+0

+1 Когда я увидел название, я сразу же подумал о Парсеке. Это отличный способ практиковать решение интересных, нетривиальных, но простых проблем. –

 Смежные вопросы

  • Нет связанных вопросов^_^