2012-04-01 9 views
4

Warum kann ich das nicht tun? Es ist die Verwendung von 'tun' in dieser Frage verboten:/ Wie kann ich anrufen Worte in meiner Liste und zur gleichen Zeit ein IO? Dank .. Das ist mein eigentlicher Code:/Haskell, kann ich Funktion ohne IO-Ausgabe mit Monaden arbeiten?

main :: IO() 
main = 
    putStr "Name of File: " >> 
    getLine >>= 
    \st -> 
    openFile st ReadMode >>= 
    \handle -> 
     hGetContents handle >>= 
     \y -> 
     words y >>= 
     \strings -> 
      strings !! 1 >>= 
      \string-> 
       putStr string 

[Bearbeiten] Lösung:

main :: IO() 
main = 
    putStr "Name of File: " >> 
    getLine >>= 
    \st -> 
    openFile st ReadMode >>= 
    \handle -> 
     hGetContents handle >>= 
     \y -> 
     return (words y) >>= 
     \strings -> 
      return (strings !! 1) >>= 
      \string-> 
       putStr string 

Antwort

7

Verwenden return (words y) statt nur words y. return umschließt einen reinen Wert (wie der [String], der words zurückgibt) in eine Monade.

Von Ihrer Formulierung klingt es wie diese Frage ist Hausaufgaben. Wenn ja, sollte es als solches markiert werden.

+0

Vielen Dank, Sie haben mein Problem gelöst: D –

6

(Diese die Frage nicht direkt beantworten, aber es wird Ihr Code mehr idiomatische und damit leichter lesbar machen.)

Sie verwenden das Muster \x -> f x >>= ... viel, kann diese (und sollte) beseitigt werden : Es ist (meistens) unnötiges Rauschen, das die Bedeutung des Codes verdunkelt. Ich werde nicht den Code verwenden, da es Hausaufgaben, aber dieses Beispiel betrachten (man beachte, dass ich mit return wie der anderen Antwort vorgeschlagen):

main = getLine >>= 
     \fname -> openFile fname ReadMode >>= 
      \handle -> hGetContents handle >>= 
       \str -> return (lines str) >>= 
       \lns -> return (length lns) >>= 
        \num -> print num 

(Er liest einen Dateinamen von dem Benutzer, und dann druckt die Anzahl der Zeilen in dieser Datei.)

Die einfachste Optimierung ist der Abschnitt, wo wir die Anzahl der Zeilen zählen (das entspricht dem Teil, wo Sie die Wörter trennen und die zweite bekommen): die Anzahl von Zeilen in einer Zeichenfolge str ist nur length (lines str) (das ist das gleiche wie length . lines $ str), so gibt es keinen Grund für uns, den Anruf an length und den Anruf anzu habengetrennt. Unser Code ist jetzt:

main = getLine >>= 
     \fname -> openFile fname ReadMode >>= 
      \handle -> hGetContents handle >>= 
       \str -> return (length . lines $ str) >>= 
       \num -> print num 

nun die nächste Optimierung auf \num -> print num ist. Dies kann als nur print geschrieben werden. (Dies wird eta conversion genannt). (Sie können darüber nachdenken als "eine Funktion, die ein Argument annimmt und print darauf aufruft, ist dasselbe wie print selbst"). Jetzt haben wir:

main = getLine >>= 
     \fname -> openFile fname ReadMode >>= 
      \handle -> hGetContents handle >>= 
       \str -> return (length . lines $ str) >>= print 

Die nächste Optimierung wir tun können, auf der monad laws basiert. Unter Verwendung der ersten können wir return (length . lines $ str) >>= print in print (length . lines $ str) (d. H. "Erstellen eines Containers, der einen Wert enthält (dies erfolgt durch return) und dann übergibt diesen Wert an print ist das gleiche wie nur übergibt den Wert an print"). Auch hier können wir die Klammer entfernen, also haben wir:

main = getLine >>= 
     \fname -> openFile fname ReadMode >>= 
      \handle -> hGetContents handle >>= 
       \str -> print . length . lines $ str 

Und schau! Wir haben eine Eta-Konvertierung, die wir tun können: \str -> print . length . lines $ str wird nur print . length . lines. Dies läßt:

main = getLine >>= 
     \fname -> openFile fname ReadMode >>= 
      \handle -> hGetContents handle >>= print . length . lines 

An diesem Punkt können wir wahrscheinlich stoppen, da dieser Ausdruck viel einfacher als unsere ursprünglichen ist (wir durch die Verwendung >=> gehen könnten halten, wenn wir wollten).Da es so viel einfacher ist, ist es auch einfacher zu debuggen (sich vorstellen, wenn wir lines zu verwenden vergessen hatte. In der ursprünglichen main wäre es nicht sehr klar sein, in der letzten offensichtlich es ist)

In Ihrem Code Sie können und sollten das Gleiche tun: Sie können Dinge wie sections (was \x -> x !! 1 ist das gleiche wie (!! 1)) und die Eta-Konvertierung und Monad-Gesetze, die ich oben verwendet.

+0

Vielen Dank für die vollständige Erklärung. Ich habe die Optimierungen auf meinen Code angewendet und reduziere ihn mehr als zehn Zeilen ehhehe. Ihr Beitrag war sehr nützlich für mich .. Danke nochmal :) –

Verwandte Themen