-- The type `IO a` is thought of as a list of instructions for the operating -- system. Following the instructions results in a value of type `a`. -- -- This file makes use of the following primitive instructions: -- -- readFile :: FilePath -> IO String -- writeFile :: FilePath -> String -> IO () -- getChar :: IO Char -- -- FilePath is defined as -- -- type FilePath = String -- -- () is pronounced "unit" and can be thought of as an empty tuple. () is a type -- that has a single value, and this value is also written as (). -- -- () is used when there is no other sensible value to return. -- -- Other useful standard functions are: -- -- putStr :: String -> IO () -- putStrLn :: String -> IO () import Data.List -- `writeTwoFiles f s` produces two files named `f++"1"` and `f++2` with the -- same content `s` -- (or rather, returns instructions to produce the files) writeTwoFiles :: FilePath -> String -> IO () writeTwoFiles file s = do writeFile (file ++ "1") s writeFile (file ++ "2") s -- `copyFile f1 f2` copies the file `f1` to the new file `f2` -- (or rather, produces instructions copy the file) copyFile :: FilePath -> FilePath -> IO () copyFile from to = do contents <- readFile from writeFile to contents -- `catFile f1 f2` reads the files `f1` and `f2` and prints their content on the -- terminal -- (or rather, produces instructions print the content) catFiles :: FilePath -> FilePath -> IO String catFiles file1 file2 = do s1 <- readFile file1 s2 <- readFile file2 return (s1++s2) -- `doTwice i` performs the instructions `i` twice -- (or rather, produces a new instruction list, in which `i` is performed twice) doTwice :: IO a -> IO (a,a) doTwice io = do x <- io y <- io return (x,y) -- `dont i` ignores the instructions `i` and does not perform any instructions -- (or rather, produces an empty instruction list) dont :: IO a -> IO () dont io = do return () -- The do keyword is not needed here... -- What does this code do? example :: IO () example = dont (writeFile "file.txt" "this is a file") -- `second is` performs the second set of instructions in `is` -- (or rather, picks out the second set of instructions and ignores the rest) second :: [IO a] -> IO a second (_:io:_) = io -- This example shows that tnstructions are normal data! This means that -- instructions can be stored in data structures such as lists. -- `sortFile f1 f2` reads the content of file `f1`, sorts its lines and writes -- the result to file `f2` sortFile :: FilePath -> FilePath -> IO () sortFile file1 file2 = do s <- readFile file1 writeFile file2 (unlines (sort (lines s))) -- myGetLine (a.k.a. `getLine`) myGetLine :: IO String myGetLine = do c <- getChar if c == '\n' then return "" else do cs <- myGetLine return (c:cs) -- This example shows that instruction lists can depend on the environment -- (in this case the user's input), and they can be built recursively. -- `mySequence_ is` (a.k.a. `sequence`) takes a list of instruction sets and -- performs them in sequence -- (or rather, concatenates a list of instruction sets to a single instruction -- set) mySequence_ :: [IO ()] -> IO () mySequence_ [] = return () mySequence_ (io:ios) = do io mySequence_ ios -- `mySequence` (a.k.a. `sequence`) is like `mySequence_`, but it also returns -- all intermediate results as a list mySequence :: [IO a] -> IO [a] mySequence [] = return [] mySequence (io:ios) = do a <- io as <- mySequence ios return (a:as) -- `writeFiles f [s1,s2 ... sx]` produces the files `f++"1"`, `f++"2"` ... -- `f++"x"` with the contents s1, s2 ... sx respectively writeFiles :: FilePath -> [String] -> IO () writeFiles file xs = sequence_ [ writeFile (file++show i) x | (x,i) <- zip xs [1..] ] -- [1..] is an infinite list, but zip stops when xs ends -- prog asks the user for a file name and some content and produces a file with -- that name and content prog :: IO () prog = do putStrLn "Which file?" file <- myGetLine putStrLn "What content?" contents <- myGetLine writeFile file contents putStrLn "Done." main = prog -- Compile this file using -- -- ghc --make ExampleIO.hs -- -- That produces an executable file named ExampleIO which will perform the -- instructions given by `prog`. -- -- See also .