2016-09-07 1 views
1

Ich spiele mit der interact-Funktion von Prelude, wollen eine einfache REPL meine Eingaben Zeile für Zeile zu bewerten, und ich kann nicht verstehen, was vor sich geht.Ich frage mich über Interaktion Verwendung

Wenn ich mache es einfach so:

main :: IO() 
main = interact interaction 

interaction :: String -> String 
interaction (x:xs) = xs 
interaction x = x 

Dann verhält es in Ordnung, und entfernt das erste Zeichen von meinem Eingang, oder gibt den Eingang, wenn es nur ein Zeichen lang ist.

Was mir ein Rätsel ist, wenn diese Zeile hinzufügen:

interaction :: String -> String 
interaction x | length x > 10 = "long word" -- this line causes problem 
interaction (x:xs) = xs 
interaction x = x 

Dann interagieren scheint nicht mehr richtig zu arbeiten. Es wartet nur auf meine Eingabe, schluckt es wartet auf einen anderen Eingang und so weiter, aber nie gibt nichts aus.

Es scheint so einfach, aber ich kann nicht sehen, was schief läuft. Irgendeine Idee?

(Auf meinem Weg habe ich GHC 7.6.3, ich weiß nicht, ob es eine gewisse Bedeutung hat.)

Antwort

3

Mit dem, was Sie geschrieben haben, Sie versuchen, die Länge des gesamten Eingangs zu berechnen Sequenz, so dass Ihr Programm warten muss, bis die gesamte Sequenz verfügbar ist.

Sie könnten ein fauler Muster-Spiel zu sehen wie diese versuchen:

interaction (x1:x2:x3:x4:x5:x6:x7:x8:x9:x10:x11:_) = "long word" 

Auf diese Weise können Sie den Rest der Eingabe ignorieren, wenn Sie wissen, dass Sie 10 Zeichen erreicht haben.

Eine sauberere/allgemeinere Alternative (von @amalloy vorgeschlagen), die für größere Längen skaliert und erlaubt eine variable Länge guard würde wie etwas sein:

interaction xs | not . null . drop 10 $ xs = "long word" 

Wenn das, was Sie wirklich wollen, um Ihren Eingang eine Zeile zu einem Zeitpunkt, und diese Nachricht für eine einzelne Zeile länger als 10 Zeichen erzeugen, können Sie Ihre Interaktion Funktion zeilenorientiert statt zeichenorientiert, zB lines und unlines vornehmen können:

main :: IO() 
main = interact (unlines . interaction . lines) 

interaction :: [String] -> [String] 
interaction (x:_) | length x > 10 = "long word" -- this is just looking at the first line 
... 

oder vielleicht, wenn Sie, dass für jede Zeile, nicht nur die ersten tun:

main :: IO() 
main = interact (unlines . map interaction . lines) 

interaction :: String -> String 
interaction x | length x > 10 = "long word" 
... 
3

interact nimmt die Gesamtheit der Standardeingabe auf einmal, als eine große Zeichenfolge. Sie rufen length auf allen stdin, und so kann Ihre Funktion nicht zurückkehren, bis Stdin vollständig erschöpft ist. Sie könnten zum Beispiel ctrl-D (unter der Annahme von Unix) drücken, um EOF zu senden, und dann wird Ihre Funktion schließlich herausfinden, welche Länge die stdin ist.

+0

ok, so ist es wegen meiner Verwendung der "Länge" -Funktion. es macht Sinn. Vielen Dank. –