Problème avec « do » Haskell
Question
J'ai écrit une fonction Haskell qui calcule le factoriel de chaque numéro dans une liste donnée et il imprime à l'écran.
factPrint list =
if null list
then putStrLn ""
else do putStrLn ((show.fact.head) list)
factPrint (tail list)
La fonction fonctionne, mais je trouve la troisième ligne un peu confus. Pourquoi pas le compilateur (GHC) a signalé une erreur sur elle car il n'y a pas de « faire » avant que la fonction « putStrLn » (quasi?)? Si je laisse de côté « faire » à partir de la 4ème ligne, une erreur apparaît comme prévu.
Je suis tout à fait nouveau pour Haskell et ses moyens, alors s'il vous plaît pardonnez-moi si je disais quelque chose trop stupide.
La solution
do putStrLn ((show.fact.head) list)
factPrint (tail list)
est en fait une autre façon d'écrire
putStrLn ((show.fact.head) list) >> factPrint (tail list)
qui, à son tour, des moyens
putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)
La notation do
est un moyen pratique de corder ces monades ensemble, sans cette autre syntaxe laid.
Si vous avez une seule instruction à l'intérieur du do
, alors vous n'êtes pas corder quoi que ce soit ensemble, et le do
est redondant.
Autres conseils
Si vous êtes nouveau à Haskell, penser à do
comme semblables aux appareils nécessaires après if
dans un langage C comme:
if (condition)
printf("a"); // braces not required
else {
printf("b"); // braces required
finish();
}
do
fonctionne de la même manière Haskell.
Peut-être qu'il serait utile d'examiner le type de factPrint et factoriser ensuite utiliser la correspondance de motif:
factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
putStrLn (show.fact.head) list
factPrint (tail list)
Donc, si factPrint retourne IO ()
, et le type de putStrLn ""
est IO ()
, alors il est parfaitement légal pour factPrint []
à l'égalité putStrLn ""
. Pas do
nécessaire -. En fait, vous pouvez simplement dire factPrint [] = return ()
si vous ne voulez pas le saut de ligne
do
est utilisé pour lier plusieurs expressions monades ensemble. Il n'a pas d'effet quand il est suivi par une seule expression.
Pour le cas être bien formé, il est seulement nécessaire que l'époque article et l'autre article ont le même type. Étant donné que les deux clauses ont le type IO ()
tel est le cas.
Le mot-clé est utilisé pour do séquençage, un if-then-else dans Haskell ne doit pas contenir un do
du tout si chaque branche est une instruction unique par exemple.
if a
then b
else c
Vous avez besoin du do
dans votre exemple que vous séquencez deux opérations sur votre branche d'autre. Si vous omettez le do
alors la déclaration de factPrint(tail list)
est considéré comme ne pas faire partie de la fonction et donc le compilateur se plaint qu'il a rencontré une déclaration inattendue.