2013-05-28 21 views
13

Sono nuovo di Haskell e ho un problema con la funzione interact. Questo è il mio programma di esempio:Funzione interazione Haskell

main :: IO() 
main = interact inputLength 

inputLength :: String -> String 
inputLength input = show $ length input 

Compila ma durante l'esecuzione non stampa l'uscita - si limita a stampare la stringa che viene passata ad esso e si sposta alla riga successiva. Quando passo il interact un'altra String -> String funzione come questa:

upperCase :: String -> String 
upperCase input = map toUpper input 

corre ok e stampa l'argomento in maiuscolo come previsto - così che cosa c'è di sbagliato con la prima funzione?

+1

penso 'interact' è ancora una bella modo di scrivere programmi da riga di comando che hanno lo scopo di funzionare con le pipe. Con 'IO' sono tentato di scrivere programmi non-componibili per utente. – luqui

risposta

32

interact :: String -> String prende una stringa contenente tutto l'input e restituisce una stringa contenente tutto l'uscita. Il motivo per cui vedi l'output dopo aver premuto entra con interact (map toUpper) è perché map toUpper si comporta pigramente - può iniziare a dare l'output prima che tutto l'input sia noto. Trovare la lunghezza di una stringa non è così - l'intera stringa deve essere conosciuta prima che qualsiasi output possa essere prodotto.

È necessario segnalare un EOF per dire che hai finito di inserire input (nella console, questo è Control-D su sistemi Unix/Mac, credo sia Control-Z su Windows), quindi ti darà la lunghezza. Oppure si può trovare la lunghezza di ogni riga dicendo così:

interact (unlines . map (show . length) . lines) 

Questo sarà sempre pigro in ogni riga, in modo da sapere è possibile ottenere un'uscita dopo ogni ingresso.

Dal agendo sulle linee è un modello così comune, mi piace definire una piccola funzione di supporto:

eachLine :: (String -> String) -> (String -> String) 
eachLine f = unlines . map f . lines 

allora si può fare:

main = interact (eachLine inputLength)