Problem mit Haskell „do“
Frage
Ich schrieb eine Haskell-Funktion, die die Fakultät von jeder Zahl in einer bestimmten Liste und druckt sie auf den Bildschirm berechnet.
factPrint list =
if null list
then putStrLn ""
else do putStrLn ((show.fact.head) list)
factPrint (tail list)
Die Funktion funktioniert, aber ich die dritte Zeile ein bisschen verwirrend finden. Warum hat nicht der Compiler (GHC) berichtete über einen Fehler, da es keine „tun“ vor der „putStrLn“ (quasi?) Funktion? Wenn ich „do“ aus der 4. Zeile weglassen, wird ein Fehler erscheint als erwartet werden.
Ich bin ganz neu in Haskell und seine Wege, pardon mir so gefallen, wenn ich etwas gesagt allzu dumm.
Lösung
do putStrLn ((show.fact.head) list)
factPrint (tail list)
ist eigentlich eine andere Art und Weise des Schreibens
putStrLn ((show.fact.head) list) >> factPrint (tail list)
, die wiederum Mittel
putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)
Die do
Notation ist ein bequemer Weg, um diese Monaden Zusammenreihung, ohne diese andere hässliche Syntax.
Wenn Sie nur eine Anweisung innerhalb des do
haben, dann Bespannen Sie nichts zusammen, und die do
ist überflüssig.
Andere Tipps
Wenn Sie neu in Haskell, denken Sie an do
ähnlich wie erforderlich Zahnspange nach if
in einer C-ähnlichen Sprache:
if (condition)
printf("a"); // braces not required
else {
printf("b"); // braces required
finish();
}
do
funktioniert auf die gleiche Art und Weise in Haskell.
Vielleicht wäre es zu Blick auf die Art von factPrint helfen, und dann Refactoring zu verwenden Mustervergleich:
factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
putStrLn (show.fact.head) list
factPrint (tail list)
Also, wenn factPrint IO ()
zurückkehrt, und die Art der putStrLn ""
ist IO ()
, dann ist es vollkommen legal für factPrint []
gleich putStrLn ""
. Keine do
erforderlich - in der Tat, die Sie gerade factPrint [] = return ()
sagen könnte, wenn Sie nicht die Newline wollen
do
wird zusammen mehrere monadische Ausdrücke zu binden. Sie hat keine Auswirkung, wenn sie von nur einem einzigen Ausdruck gefolgt.
Für die, wenn sein wohlgeformt es nur notwendig ist, dass die damalige Klausel und die else-Klausel desselben Typen haben. Da beide Klauseln den Typ IO ()
haben, ist dies der Fall.
Das Schlüsselwort kann zur Sequenzierung verwendet wird, ein if-then-else in Haskell muss nicht ein do
überhaupt enthält, wenn jeder Zweig eine einzelne Anweisung zB ist.
if a
then b
else c
Sie müssen die do
in Ihrem Beispiel, wie Sie zwei Operationen auf dem anderen Zweig sequenzieren. Wenn Sie die do
dann die factPrint(tail list)
Aussage gilt als nicht Teil der Funktion und damit der Compiler beschwert sich auslassen, da es eine unerwartete Aussage gestoßen wird.