-- 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 f content = do writeFile (f ++ "1") content writeFile (f ++ "2") content -- `copyFile f1 f2` copies the file `f1` to the new file `f2` -- (or rather, produces instructions copy the file) copyFile :: FilePath -> FilePath -> IO () copyFile file1 file2 = do str <- readFile file1 writeFile file2 (reverse str) -- `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 () catFiles file1 file2 = do str1 <- readFile file1 str2 <- readFile file2 putStrLn (str1 ++ str2) -- `doTwice i` performs the instructions `i` twice -- (or rather, produces a new instruction list, in which `i` is performed twice) doTwice :: IO () -> IO () doTwice instr = do instr instr doTwice' :: IO a -> IO (a,a) doTwice' instr = do a <- instr b <- instr return (a,b) -- `dont i` ignores the instructions `i` and does not perform any instructions -- (or rather, produces an empty instruction list) dont :: IO a -> IO () dont instr = return () -- dont (writeFile ...) -- `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 (i:i2:is) = i2 -- 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 str <- readFile file1 writeFile file2 (myFun str) myFun :: String -> String myFun str = unlines (sort (lines str)) -- myGetLine (a.k.a. `getLine`) myGetLine :: IO String myGetLine = do c <- getChar if c == '\n' then return "" else do line <- myGetLine return (c:line) -- This example shows that instruction lists can depend on the environment -- (in this case the user's input), and they can be built recursively. -- doTwice myGetLine -- `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_ (i:is) = do i mySequence_ is mySequence :: [IO a] -> IO [a] mySequence [] = return [] mySequence (i:is) = do a <- i as <- mySequence is return (a:as) -- `mySequence` (a.k.a. `sequence`) is like `mySequence_`, but it also returns -- all intermediate results as a list -- `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 strs = mySequence_ [writeFile (file ++ show i) str | (str,i) <- zip strs [1..]] -- zip an infinite list -- Note how we use `mySequence_` and list comprehension the way that for loops -- are used in other languages -- prog asks the user for a file name and some content and produces a file with -- that name and content -- Define main and compile main = do putStrLn "Which file name?" file <- myGetLine putStrLn "What content?" content <- myGetLine writeFile file content