Input and Output
Extend the “guess a number” game to generate the bounds randomly.
Write
sequence
andsequence_
using(>>=)
instead ofdo
-notation.sequence :: [IO a] -> IO [a] sequence [] = return [] sequence (a:acts) = a >>= \x -> sequence acts >>= \xs -> return (x:xs) -- or using a foldr: sequence :: [IO a] -> IO [a] sequence = foldr (\a r -> a >>= \x -> r >>= \xs -> return (x:xs)) (return []) -- sequence_ just throws away the results: sequence_ :: [IO ()] -> IO () sequence_ = foldr (\a r -> a >>= \_ -> r) (return ()) -- or even: sequence_ :: [IO ()] -> IO () sequence_ = foldr (>>) (return ())
Write a function which prompts for a filename, reads the file with this name, splits the file into a number of lines, splits each line in a number of words separated by
' '
(a space), and prints the total number of lines and words.linesAndWords :: IO () = do putStrLn "Path to file:" linesAndWords <- getLine fp <- readFile fp fileContents let n = length . lines $ fileContents = length . words $ fileContents m putStrLn $ "Number of lines: " ++ show n putStrLn $ "Number of words: " ++ show m main :: IO () = linesAndWords main
Given the function
getInt :: IO Int
, which reads an integer value from standard input, write a program that results in the following input/output behaviour (the3
has been typed in by the user):Give a number: 3 1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 ... 10 * 3 = 30 Goodbye
Try to use
sequence_
,mapM_
orforM_
.= do putStr "Give a number: " tabulate <- getInt n mapM_ (putStrLn . f n) [1..10] putStrLn "Goodbye" where f :: Int -> Int -> String = unwords [ show i, "*", show n, "=", show $ i * n] f n i
Write a function of type
[FilePath] −> FilePath −> IO ()
which concatenates a list of files to a specific target file: the first parameter is a list of filenames and the second parameter the name of the target file. Do not use the functionappendFile
.Write a program that first asks for the name of the target file, and then continues asking for names of files to be appended to that file until an empty line is entered. Note that the target files may be one of the source files!
If we know that none of the source files equals the target file we may do a bit better using the function
appendFile
fromSystem.IO
. Change the function you have written above using this function. What are the advantages and disadvantages of this approach?
Loading Binary Trees from a File
Consider usual type of binary trees
data Tree a = Leaf a
| Node (Tree a) a (Tree a)
deriving (Show,Read,Eq)
and let “myTree.txt” be a text file that stores (the string
representation as given by Show) of a Tree Int
.
We will write a short program main :: IO ()
that:
- Loads the tree from “myTree.hs” in memory
- asks the user for an number (an Int)
q
- prints if
q
appears in the tree or not.
You may use that
- the function
readFile :: FilePath -> IO String
can load the data from a file (as specified by the path) into aString
, - that the function
putStrLn :: String -> IO ()
can print aString
to standard output, and - that the function
getLine :: IO String
that can read aString
from standard input.
Write a function
readTree :: IO (Tree Int)
that only performs step 1. from the above descriptionreadTree :: IO (Tree Int) = do s <- readFile "myTree.txt" readTree return $ read s -- or using that 'IO' is a Functor: = fmap read $ readFile "myTree.txt" readTree -- or = read <$> readFile "myTree.txt" readTree
Now write a full implementation of
main :: IO ()
that usesreadTree
and performs all steps of the program sketched above.main :: IO () = do main <- readTree t putStrLn "Please input a number." <- getLine qs let q = read qs putStrLn $ show (q `elem` elems t) -- or, again using that IO is a Functor: main :: IO () = do main <- readTree t putStrLn "Please input a number." <- read <$> getLine q putStrLn $ show (q `elem` elems t)