Problema con Haskell de “hacer”
Pregunta
Me escribió una función Haskell que calcula el factorial de cada número en una lista dada y lo imprime a la pantalla.
factPrint list =
if null list
then putStrLn ""
else do putStrLn ((show.fact.head) list)
factPrint (tail list)
La función funciona, pero me parece que la tercera línea un poco confuso. ¿Por qué el compilador (GHC) no ha informado de un error en él ya que no hay "hacer" antes de la función "putStrLn" (cuasi?)? Si omito "hacer" de la cuarta línea, se producirá un error como se esperaba.
Soy bastante nuevo en Haskell y sus formas, así que me Por favor, perdón si he dicho algo demasiado tonto.
Solución
do putStrLn ((show.fact.head) list)
factPrint (tail list)
En realidad, es otra manera de escribir
putStrLn ((show.fact.head) list) >> factPrint (tail list)
que, a su vez, significa
putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)
La notación do
es una manera conveniente de encadenar estas mónadas juntos, sin esta otra sintaxis feo.
Si usted tiene solamente una declaración dentro del do
, entonces usted no está de encordar nada juntos, y el do
es redundante.
Otros consejos
Si usted es nuevo en Haskell, piensa en do
como similar a los apoyos requeridos después if
en un C-como el lenguaje:
if (condition)
printf("a"); // braces not required
else {
printf("b"); // braces required
finish();
}
do
funciona de la misma manera en Haskell.
Tal vez ayudaría a mirar el tipo de factPrint, y luego a refactor patrón de uso de juego:
factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
putStrLn (show.fact.head) list
factPrint (tail list)
Por lo tanto, si factPrint vuelve IO ()
, y el tipo de putStrLn ""
es IO ()
, entonces es perfectamente legal para factPrint []
al igual putStrLn ""
. No se requiere do
- de hecho, sólo podría decir factPrint [] = return ()
si no desea que el salto de línea final
do
se utiliza para atar múltiples expresiones monádicos juntos. No tiene ningún efecto cuando seguido por sólo una única expresión.
En el caso de ser bien formado sólo es necesario que el entonces cláusula y la cláusula-demás tienen el mismo tipo. Dado que ambas cláusulas tienen el tipo IO ()
este es el caso.
La DO palabra clave se utiliza para la secuenciación, un if-then-else en Haskell no tiene que contener una do
en absoluto si cada rama es una sola instrucción por ejemplo.
if a
then b
else c
Se necesita el do
en su ejemplo como se Secuenciando dos operaciones en su sucursal más. Si se omite el do
entonces la declaración factPrint(tail list)
se considera que no sea parte de la función y por lo tanto el compilador se queja como se le encontró una declaración inesperada.