Где найти упражнения по программированию для аппликативных функторов?
Я читал о прикладных функторах, особенно в функциональной Жемчужине Макбрайда и Патерсона. Но я хотел бы укрепить свое понимание, сделав несколько упражнений. Я бы предпочел упражнения по программированию, но упражнения для доказательства тоже в порядке. какие упражнения помогут мне научиться эффективно программировать с аппликативные функторы?
отдельные упражнения в порядке, как и указатели на упражнения, перечисленные в другом месте.
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. Он поставляется с хорошим объяснением с нуля и некоторыми упражнениями по пути.