Подтвердить что ты не робот

Где найти упражнения по программированию для аппликативных функторов?

Я читал об аппликативных функторах, особенно в Functional Pearl от McBride и Paterson. Но я хотел бы укрепить свое понимание, выполняя некоторые упражнения. Я бы предпочел программирование, но упражнения на упражнения тоже в порядке. Какие упражнения помогут мне научиться эффективно программировать с помощью аппликативных функторов?

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

4b9b3361

Ответ 1

Кажется забавным поставить некоторые вопросы в качестве ответа. Это весело, при взаимодействии между 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

Предположим, что мы представляем a 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}

и построим

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), лишенной дубликатов в любой строке, столбце или поле.

Ответ 2

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

Eg. для выражений:

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

Ответ 3

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