2012-04-20 17 views
27

He estado leyendo acerca de los funtores aplicativos, especialmente en el Functional Pearl de McBride y Paterson. Pero me gustaría solidificar mi comprensión haciendo algunos ejercicios. Preferiría ejercicios de programación, pero los ejercicios de prueba también están bien. ¿Qué ejercicios me ayudarán a aprender a programar de manera efectiva con los funtores aplicativos?¿Dónde encontrar ejercicios de programación para funtores aplicativos?

Los ejercicios individuales son correctos, como lo son los consejos para los ejercicios enumerados en otra parte.

+3

No puedo sugerir ejercicios, pero podría ver los funtores aplicativos que no son mónadas (una pregunta crucial parece ser "¿por qué diseñar un functor aplicativo cuando es menos poderoso que una mónada?"). El aplicativo de errores múltiples (en Paterson y McBride) es uno, también hay analizadores de Doaitse Swierstra, uno de animación _Active_ en Andy Gill y Kevin Matledge's Chalkboard y creo que Andy Gill y sus colegas 'Kansas Lava se basan en un funcionador aplicativo. –

Respuesta

20

Parece divertido publicar algunas preguntas como respuesta. Este es divertido, en la interacción entre Applicative y Traversable, basado en sudoku.

(1) Considerar

data Triple a = Tr a a a 

Construct

instance Applicative Triple 
instance Traversable Triple 

para que la instancia Applicative hace "vectorización" y la instancia Traversable trabaja de izquierda a derecha. No olvides construir una instancia adecuada de Functor: comprueba que puedes extraerla de la instancia Applicative o Traversable. Puede encontrar

newtype I x = I {unI :: x} 

útil para este último.

(2) Considérese

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

Demostrar que

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

definen ahora

type Zone = Triple :. Triple 

Supongamos que representan una Board como una zona vertical de zonas horizontales

type Board = Zone :. Zone 

Muestre cómo reorganizarlo como una zona horizontal de zonas verticales, y como un cuadrado de cuadrados, utilizando la funcionalidad traverse.

(3) Considere

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

o alguna otra construcción adecuada (teniendo en cuenta que el comportamiento de la biblioteca para Monoid | Quizás | es inapropiada).Construir

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

e implementar

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

que consume y ofrece un personaje si es aceptada por un predicado dado.

(4) Implementar un analizador que consume cualquier cantidad de espacios en blanco, seguido de un solo dígito (0 representa espacios en blanco)

square :: Parse Int 

Uso pure y traverse para construir

board :: Parse (Board Int) 

(5) Considere los functors constantes

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

y constru ct

instance Monoid a => Applicative (K a) 

a continuación, utilizar traverse para implementar

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

Construct newtype envolturas para Bool expresar sus estructuras monoides conjuntivos y disyuntivos. Use crush para implementar versiones de any y all que funcionen para cualquier funcionador Traversable.

(6) Implementar

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

el cálculo de la lista de valores que se producen más de una vez. (No es completamente trivial.) (Hay una bonita manera de hacer esto utilizando el cálculo diferencial, pero eso es otra historia.)

(7) Implementar

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

el que comprobar si una tabla es (1) completo solamente de dígitos en [1..9] y (2) desprovistos de duplicados en cualquier fila, columna o casillero.

+0

¡Grandes ejercicios! – luqui

5

Revisa el Typeclassopedia. Viene con una buena explicación desde cero y algunos ejercicios en el camino.

4

Por ejemplo: Applicative Functors

+0

Este enlace parece estar muerto, pero [esta es la página de Internet Archive Wayback Machine] (https://web.archive.org/web/*/http://www.cis.upenn.edu/~cis194/lectures/ *): [Functors] (https://web.archive.org/web/20130803145920/http://www.cis.upenn.edu/~cis194/lectures/09-functors.html); [Functors Aplicativos] (https://web.archive.org/web/20130803134207/http://www.cis.upenn.edu/~cis194/lectures/10-applicative.html) –

12

Una gran manera de practicar es usar Parsec en un aplicativo en lugar de un estilo monádico. La mayoría de los analizadores son puramente aplicativos, por lo que no debería necesitar usar la notación do.

Por ejemplo. para expresiones:

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

Tengo curiosidad- -puede dar algunos ejemplos comunes o al menos razonables que * no * puede analizar con un funcionador aplicativo pero puede hacerlo con una mónada? –

+7

@TikhonJelvis, * formalmente * son equivalentes en potencia, al menos sobre un alfabeto finito, pero de una manera patológica (ambos admiten gramáticas infinitas). Pero un buen ejemplo de dónde necesitarías (razonablemente) una mónada sería si tuvieras un lenguaje que pudiera definir nuevos constructos gramaticales que deberían tenerse en cuenta más adelante en el análisis.'Applicative' no puede cambiar su * estructura * en función de su * contenido *,' mónada' puede. – luqui

+0

+1 Cuando vi el título, inmediatamente pensé en Parsec. Es una excelente manera de practicar la resolución de problemas interesantes, no triviales, pero simples. –

Cuestiones relacionadas