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

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

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

4 ответов


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


отличный способ практиковать-использовать 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

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