Domanda

ho scritto una funzione Haskell che calcola il fattoriale di ogni numero in una data lista e lo stampa sullo schermo.

factPrint list =
if null list
    then putStrLn ""
    else do putStrLn ((show.fact.head) list)
        factPrint (tail list)

La funzione funziona, ma trovo la terza linea un po 'di confusione. Perché il compilatore (GHC) non ha segnalato un errore su di essa dal momento che non c'è un "fare" prima che la funzione "putStrLn" (quasi?)? Se Tralascio "sì" dal 4 ° linea, un errore si apre come previsto.

Sono abbastanza nuovo per Haskell e dei suoi modi, quindi per favore mi perdoni se ho detto qualcosa di troppo stupido.

È stato utile?

Soluzione

do putStrLn ((show.fact.head) list)
   factPrint (tail list)

è in realtà un altro modo di scrivere

putStrLn ((show.fact.head) list) >> factPrint (tail list)

, che, a sua volta, significa

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

La notazione do è un modo conveniente di infilare queste monadi insieme, senza quest'altra sintassi brutto.

Se si dispone di una sola istruzione all'interno della do, allora non siete tesatura niente insieme, e il do è ridondante.

Altri suggerimenti

Se siete nuovi a Haskell, pensare a do come simile a parentesi graffe richiesti dopo if in un linguaggio simile al C:

if (condition)
  printf("a"); // braces not required
else {
  printf("b"); // braces required
  finish();
}

do funziona allo stesso modo in Haskell.


Forse sarebbe d'aiuto a guardare il tipo di factPrint, e quindi refactoring di utilizzare pattern matching:

factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
  putStrLn (show.fact.head) list
  factPrint (tail list)

Quindi, se factPrint torna IO (), e il tipo di putStrLn "" è IO (), allora è perfettamente legale per factPrint [] alla parità putStrLn "". No do richiesto -. In realtà, si può solo dire che factPrint [] = return () se non si desidera che il fine riga

do viene utilizzato per legare più espressioni monadici insieme. Non ha alcun effetto se seguito da una sola espressione.

Per il caso di essere ben formato è necessario soltanto che l'allora clausola e l'altro clausola sono dello stesso tipo. Poiché entrambe le clausole di avere il tipo IO () questo è il caso.

La parola chiave do viene utilizzato per il sequenziamento, un if-then-else in Haskell non deve contenere una do a tutti se ogni ramo è una singola istruzione ad es.

if a
  then b
  else c

È necessario il do nel tuo esempio, come si sequenziazione due operazioni sul ramo altro. Se si omette il do poi la dichiarazione factPrint(tail list) è considerato non essere parte della funzione e quindi il compilatore si lamenta come è incontrato una dichiarazione inaspettata.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top