Go to the first, previous, next, last section, table of contents.


Ein- und Ausgabe

Vordefinierte EA-Aktionen

Zur Erinnerung: mit Hilfe des abstrakten Typs `IO val' werden Aktionen beschrieben, die Ein- oder Ausgaben vornehmen. Allgemeiner: ..., die mit dem Betriebssystem oder der Umgebung kommunizieren.

----------------------------------------------------------------------
> data IO val
----------------------------------------------------------------------

Ein Element vom Typ `IO val' beschreibt eine EA-Aktion, die einen Wert vom Typ `val' zurückgibt.

Vordefinierte Ausgabefunktionen (teilweise aus der Bibliothek `IOSupport'):

----------------------------------------------------------------------
> putChar       :: Char -> IO ()
> putStr        :: String -> IO ()
> putLine       :: String -> IO ()              -- IOSupport
> print         :: (Text a) => a -> IO ()
----------------------------------------------------------------------

Vordefinierte Eingabefunktionen (teilweise aus der Bibliothek `IOSupport'):

----------------------------------------------------------------------
> getChar       :: IO Char
> getLine       :: IO String                    -- IOSupport
> readLine      :: (Text a) => IO a             -- IOSupport
----------------------------------------------------------------------

Vordefinierte Operationen auf Dateien.

----------------------------------------------------------------------
> type FilePath =  String
>
> readFile      :: FilePath -> IO String
> writeFile     :: FilePath -> String -> IO ()
> appendFile    :: FilePath -> String -> IO ()
----------------------------------------------------------------------

Beachte: `readFile' arbeitet `lazy': Der Einleseprozeß wird erst durch den Zugriff auf die Zeichenkette angestoßen.

Verknüpfung von EA-Aktionen:

----------------------------------------------------------------------
> done          :: IO ()                        -- IOSupport
> return        :: a -> IO a
> (>>)          :: IO a -> IO b -> IO b
> (>>=)         :: IO a -> (a -> IO b) -> IO b
----------------------------------------------------------------------

C-Programmierer. `return' bleibt `return'; `act1 >> act2' läßt sich als `act1; act2' lesen und `act1 >>= \x -> act2' als `x = act1; act2'.

Jedes Haskell Programm muß den Bezeichner `main :: IO ()' definieren.

----------------------------------------------------------------------
> main          =  print [ (i, i^2) | i <- [0 .. 9] ]
----------------------------------------------------------------------

Beim Programmstart wird die an `main' gebundene Aktion (respektive die Beschreibung der Aktion) ausgeführt.

Beispiel: Das Programm fragt den Benutzer nach einem Dateinamen und gibt den Inhalt der Datei auf dem Bildschirm aus.

----------------------------------------------------------------------
> askFor        :: String -> IO String
> askFor s      =  putStr s >> getLine
>
> main          :: IO ()
> main          =  askFor "filename: "          >>= \file ->
>                  readFile file                >>= \cnts ->
>                  putStr cnts
----------------------------------------------------------------------

`sequence' und `accumulate'

Die Funktionen `sequence' und `accumulate' führen Listen von Aktionen aus.

----------------------------------------------------------------------
> sequence              :: [IO a] -> IO ()
> sequence []           =  done
> sequence (a:as)       =  a >> sequence as
>
> accumulate            :: [IO a] -> IO [a]
> accumulate []         =  return []
> accumulate (a:as)     =  a                    >>= \v ->
>                          accumulate as        >>= \vs ->
>                          return (v:vs)
----------------------------------------------------------------------

`sequence' und `accumulate' werden gerne mit Listenbeschreibungen kombiniert.

----------------------------------------------------------------------
> askForMany            :: [String] -> IO [String]
> askForMany xs         =  accumulate [ askFor s | s <- xs ]
----------------------------------------------------------------------

Bibliothek `LibSystem'

Die Bibliothek `LibSystem' definiert Operationen, um mit dem Betriebssystem zu kommunizieren.

----------------------------------------------------------------------
> data ExitCode =  ExitSuccess | ExitFailure Int
>
> getArgs       :: IO [String]
> getProgName   :: IO String
> getEnv        :: String -> IO String
> system        :: String -> IO ExitCode
> exitWith      :: ExitCode -> IO a
----------------------------------------------------------------------

Fehlerbehandlung

EA-Aktionen können fehlschlagen: eine Datei ist z.B. nicht vorhanden oder nicht lesbar. Derartige Fehler können abgefangen oder auch selbst ausgelöst werden.

----------------------------------------------------------------------
> data IOError13        = AlreadyExists String
>                       | ...
>                       | NoSuchThing String
>                       | ...
>                       | UserError String
>                       | EOF
>
> failWith              :: IOError13 -> IO a
> handle                :: IO a -> (IOError13 -> IO a) -> IO a
----------------------------------------------------------------------

Abgeleitete Operationen:

----------------------------------------------------------------------
> fail                  :: String -> IO a
> fail                  =  failwith . UserError
>
> try                   :: IO a -> IO (Either IOError13 a)
> try p                 =  (p >>= (return . Right))
>                              `handle` (return . Left)
>
> either                :: (a -> c) -> (b -> c)
>                       -> (Either a b) -> c
> either f g (Left x)   =  f x
> either f g (Right x)  =  g x
----------------------------------------------------------------------

Typische Anwendung von `try' und `either':

----------------------------------------------------------------------
    try a >>= either (\err -> ...) (\ok -> ...)
----------------------------------------------------------------------

Beispiel: Ausgabe einer Datei mit Fehlerbehandlung.

----------------------------------------------------------------------
> askFor        :: String -> IO String
> askFor s      =  putStr s                     >>
>                  getLine                      `handle` \err ->
>                  case err of
>                  EOF -> exitWith ExitSuccess
>                  _   -> failWith err
>
> main          =  askFor "filename: "          >>= \file ->
>                  try (readFile file)          >>=
>                  either
>                  (\err  -> case err of
>                      NoSuchThing _ ->
>                          putLine "file does not exist"
>                      _ -> failWith err)
>                  (\cnts -> putStr cnts)
----------------------------------------------------------------------

Beispiele: `echo' und `cat'

Beispiel: Realisierung des UNIX-Kommandos `echo'.

    NAME
         echo - display a line of text
    SYNOPSIS
         echo [-n] [string ...]

Haskell Programm:

----------------------------------------------------------------------
> import LibSystem
>
> main          =  getArgs >>= echo
>
> echo []       =  done
> echo ("-n":x) =  putStr  (unwords x)
> echo x        =  putLine (unwords x)
----------------------------------------------------------------------

Beispiel: Realisierung des UNIX-Kommandos `cat' (vereinfacht).

    NAME
         cat - concatenate files and print on the standard output
    SYNOPSIS
         cat [-n] [file...]

Haskell Programm:

----------------------------------------------------------------------
> import Support
> import IOSupport
> import LibSystem
>
> main          =  getArgs >>= cat
>
> cat           :: [String] -> IO ()
> cat []        =  done
> cat ("-n":x)  =  sequence [ copy True f  | f<-x ]
> cat x         =  sequence [ copy False f | f<-x ]
>
> copy          :: Bool -> FilePath -> IO ()
> copy b f      =  readFile f                   >>= \cnts ->
>                  sequence [
>                      onlyif b (putLineNo n)   >>
>                      putLine l
>                  | (n, l)<-zip [1.. ] (lines cnts) ]
>
> putLineNo     :: Int -> IO ()
> putLineNo n   =  putStr (rjustify 6 (show n) ++ "  ")
>
> onlyif        :: Bool -> IO () -> IO ()
> onlyif b a    =  if b then a else done
----------------------------------------------------------------------


Go to the first, previous, next, last section, table of contents.