2013-08-10 19 views
5

Sto cercando di capire Haskell IO ma questa caratteristica di stdin in ultima analisi, mi confonde: Quando provo ad usare qualche funzione come getContents, per esempio in:Haskell IO - maniglia chiusa

let main = do x<-getContents; putStrLn x 

ho la errore seguente:

hGetContents: illegal operation (handle is closed) 

Come dovrei fare IO con questo? C'è qualche correzione o dovrei cercare un'altra funzione di I/O analogica?

risposta

3

Ti suggerisco di indagare anche su un approccio alternativo. Esistono alcuni problemi inerenti a getContents e operazioni simili:

  1. È possibile avere un handle non valido: un handle già chiuso. Questo è comune nella maggior parte delle lingue, ma possiamo fare di meglio. Idealmente, vorremmo essere sicuri che una volta chiusa una maniglia, non potremmo utilizzarla ulteriormente.
  2. getContents è un lazy IO, che significa (tra gli altri problemi) che:
    • Abbiamo poco o nessun controllo di when (if) the handle is closed.
    • Durante l'elaborazione della stringa restituita da getContents, i dati vengono letti utilizzando le operazioni lazy IO. Ciò significa che all'interno dei calcoli puri possiamo ottenere effetti ed errori IO.

Un'alternativa più sicura è quella di utilizzare un altro concetto, chiamato iteratees, conduits o tubi. L'idea è che descrivi i tuoi componenti come cose che leggono alcuni dati di input e/o scrivi output e poi li combinano insieme. Questo ti permette di scrivere codice molto robusto ed elegante.

7

getContents == hGetContents stdin. Infatti hGetContents segna il suo handle (semi-) chiuso e questo significa che qualsiasi tentativo di leggere da stdin di nuovo avrà esito negativo.

Date un'occhiata al After using getContents nel Haskell User Guide

+0

E giustamente, perché anche Haskell non può cambiare il fatto che ciò che si digita sulla tastiera può essere letto solo una volta. – Ingo

4

This does not reproduce in normal operation

Se si tenta di utilizzare getContents dall'interno ghci, come ti sembra di fare, questo è esattamente ciò che accadrà quando lo si utilizza la seconda volta in giro. La prima chiamata imposterà lo handle nello stato (semi) closed e tutti i successivi tentativi di utilizzo falliranno.