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