2010-01-20 21 views
56

En una reciente answer to a style question, escribí¿Cómo se usa Control.Applicative para escribir Haskell más limpio?

main = untilM (isCorrect 42) (read `liftM` getLine) 

y

isCorrect num guess = 
    case compare num guess of 
    EQ -> putStrLn "You Win!" >> return True 
    ... 

Martijn alternativas amablemente sugeridas:

main = untilM (isCorrect 42) (read <$> getLine) 

EQ -> True <$ putStrLn "You Win!" 

Qué patrones comunes en código Haskell se puede aclarar mediante abstracciones de Control.Applicative ? ¿Cuáles son las reglas útiles para tener en cuenta para usar Control.Applicative effective?

Respuesta

42

Básicamente, las mónadas también son funcionadores aplicativos [1]. Por lo tanto, cada vez que se encuentre usando liftM, liftM2, etc., puede encadenar los cálculos usando <*>. En cierto sentido, puede pensar en funtores aplicativos como análogos a las funciones. Una función pura f se puede levantar haciendo f <$> x <*> y <*> z.

En comparación con las mónadas, los funtores aplicativos no pueden ejecutar sus argumentos de forma selectiva. Los efectos secundarios de todos los argumentos se llevarán a cabo.

import Control.Applicative 

ifte condition trueClause falseClause = do 
    c <- condition 
    if c then trueClause else falseClause 

x = ifte (return True) (putStrLn "True") (putStrLn "False") 

ifte' condition trueClause falseClause = 
    if condition then trueClause else falseClause 

y = ifte' <$> (pure True) <*> (putStrLn "True") <*> (putStrLn "False") 

x solamente emite True, mientras que y salidas True y False secuencialmente.

[1] The Typeclassopedia. Muy recomendable.

[2] http://www.soi.city.ac.uk/~ross/papers/Applicative.html. Aunque este es un trabajo académico, no es difícil de seguir.

[3] http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors. Explica el trato muy bien.

[4] http://book.realworldhaskell.org/read/using-parsec.html#id652399. Muestra cómo la biblioteca monótona Parsec también se puede usar de forma aplicativa.

+3

Ese es el único lugar que he visto donde se explica la diferencia entre 'Monad' y' Applicative' (en términos de lo que puedes expresar con cada uno). ¡Gran trabajo! ¿Podemos llamar 'ifte' con las funciones de aplicación:' z = ifte <$> ... '? –

+1

'ifte' ya es una función monádica, por lo que no hay mucho más que levantarlo una vez más. –

+3

Puede escribir "ifte" <$> (True puro) "como" ifte "Verdadero" - "puro" rara vez es necesario en combinación con "<$>" y "<*>" (si lo tiene). – Martijn

45

Hay mucho que decir en respuesta a su pregunta, sin embargo, ya que ha preguntado, ofreceré esta "regla práctica".

Si está utilizando do -notación y sus valores generados [1] no se utilizan en las expresiones que está secuenciando [2], entonces ese código puede transformarse a un estilo Aplicativo. De manera similar, si usa uno o más de los valores generados en una expresión que está secuenciada, entonces debe usar Monad y Applicative no es lo suficientemente fuerte para lograr el mismo código.

Por ejemplo, veamos el siguiente código:

do a <- e1 
    b <- e2 
    c <- e3 
    return (f a b c) 

vemos que en ninguna de las expresiones a la derecha de <- hacer cualquiera de los valores generados (a, b, c) aparecen. Por lo tanto, podemos transformarlo utilizando el código Aplicativo.He aquí una posible transformación:

f <$> e1 <*> e2 <*> e3 

y otro:

liftA3 f e1 e2 e3 

Por otro lado, tomar esta pieza de código, por ejemplo:

do a <- e1 
    b <- e2 a 
    c <- e3 
    return (f b c) 

Este código no se puede utilizar Applicative [3 ] porque el valor generado a se usa más adelante en una expresión en la comprensión. Esto debe usar Monad para obtener su resultado: intente factorizarlo en Applicative para tener una idea de por qué.

Hay algunos detalles más interesantes y útiles sobre este tema, sin embargo, sólo destinados a dar a esta regla general mediante el cual puede deslizarse sobre una -comprehension do y determinar con bastante rapidez si puede ser un factor en Applicative código de estilo .

[1] Los que aparecen a la izquierda de <-.

[2] Expresiones que aparecen a la derecha de <-.

[3] en sentido estricto, algunas partes de él podrían, por factorizar e2 a.

+12

A veces puede mezclar Monad y operadores aplicables si le gusta el estilo aplicativo. Su segundo bloque do se puede escribir 'f <$> (e1 >> = e2) <*> e3' – AndrewC

+3

+1 para ejemplos concretos de cuando el Aplicativo es suficiente y cuando se requiere Monad. – sjy

Cuestiones relacionadas