2009-10-20 7 views
4

J'ai écrit une fonction Haskell qui calcule la factorielle de chaque nombre dans une liste donnée et l'imprime à l'écran.Problème avec le "do" de Haskell

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 confuse. Pourquoi le compilateur (GHC) n'a-t-il pas signalé d'erreur puisqu'il n'y a pas de "do" avant la fonction "putStrLn" (quasi?)? Si j'omets "do" de la 4ème ligne, une erreur apparaît comme prévu. Je suis assez nouveau à Haskell et ses façons, alors s'il vous plaît pardonnez-moi si j'ai dit quelque chose de trop stupide.

Répondre

11
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, signifie

putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list) 

La notation do est un moyen pratique de enfilant ces monades ensemble, sans cet autre laid syntaxe.

Si vous n'avez qu'une seule instruction à l'intérieur du do, vous ne ficelez rien ensemble et le do est redondant.

3

Le mot-clé do est utilisé pour le séquençage, un if-then-else dans Haskell ne doit pas nécessairement contenir de do si chaque branche est une instruction unique, par exemple.

if a 
    then b 
    else c 

Vous devez le do dans votre exemple que vous séquencez deux opérations sur votre branche d'autre. Si vous omettez le do, l'instruction factPrint(tail list) est considérée comme ne faisant pas partie de la fonction et le compilateur se plaint alors qu'il a rencontré une instruction inattendue.

+0

'do' est ici _not_ une fonction, c'est un mot-clé. –

+0

De même, 'si a alors b else c' et' factPrint (queue list) 'ne sont pas des instructions, ce sont des expressions. –

4

do est utilisé pour attacher plusieurs expressions monadiques ensemble. Il n'a aucun effet lorsqu'il est suivi d'une seule expression. Pour le si bien formé, il suffit que la clause then et la clause else aient le même type. Puisque les deux clauses ont le type IO() c'est le cas.

5

Si vous êtes nouveau à Haskell, penser à do comme semblables aux appareils nécessaires après if dans une langue de type C:

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 retourne factPrint IO(), et le type de putStrLn "" est IO(), puis il est parfaitement légal que factPrint [] soit égal à putStrLn "". Non do requis - en fait, vous pourriez simplement dire factPrint [] = return() si vous ne vouliez pas le retour à la ligne.