Thinking Functionally with Haskell

Read Thinking Functionally with Haskell for Free Online Page B

Book: Read Thinking Functionally with Haskell for Free Online
Authors: Richard Bird
words problem of the previous chapter. There we defined a function commonWords :: Int -> String -> String
    such that commonWords n took a text string and returned a string giving a table of the n most common words in the text. The following program reads the text from a file, and writes the output to a file. The type FilePath is another synonym for a list of characters:
    cwords :: Int -> FilePath -> FilePath -> IO()
    cwords n infile outfile
    = do {text <- readFile infile;
    writeFile outfile (commonWords n text);
    putStrLn "cwords done!"}
    Evaluating, for example
    ghci> cwords 100 "c:\\WarAndPeace" "c:\\Results"
    on a Windows platform will cause the file c:\WarAndPeace to be read, and the results printed to c:\Results . The program also prints a message to the terminal. The two component functions of the definition above have types
    readFile :: FilePath -> IO String
    writeFile :: FilePath -> String -> IO ()
    Suppose that we didn’t want to call cwords from within an interactive session, but to use it as a stand-alone program. Here is one way. We need to define a value for an identifier main of type IO () . Here is such a program:
    main
    = do {putStrLn "Take text from where:";
    infile <- getLine;
    putStrLn "How many words:";
    n <- getLine;
    putStrLn "Put results where:";
    outfile <- getLine;
    text <- readFile infile;
    writeFile outfile (commonWords (read n) text);
    putStrLn "cwords done!" }
    For an explanation of read see Exercise H. Suppose the common words script is stored in the file cwords.lhs . We can compile it with GHC, the Glasgow Haskell Compiler: $ ghc cwords.lhs
    The compiled program will be stored in the file cwords.exe . To run the program under Windows, type $ cwords
    and follow the instructions.
2.6 Modules
    Suppose we thought that the function commonWords was sufficiently useful that we wanted to incorporate it into other scripts. The way to do this is to turn the common words script into a module . First, we rewrite the script in the following way:
    module CommonWords (commonWords) where
    import Data.Char (toLower)
    import Data.List (sort,words)
    ...
    commonWords :: Int -> String -> String
    ...
    The module declaration is followed by the name of the module, which must begin with a capital letter. Furthermore, the script has to be stored in a file called CommonWords.lhs to enable Haskell to find the module (at least, if you are using literate scripts; otherwise it would be CommonWords.hs ). Following the name of the module is a list of exports , the functions, types and other values you want to be able to export to other scripts. The list of exports has to be enclosed in parentheses. Here we just export one function, commonWords . The exports are the only things defined in the module that are visible in other modules. Omitting the export list, and the surrounding parentheses, means that everything in the module is exported.
    We can then compile the module using GHC and then import it into other scripts with the declaration import CommonWords (commonWords)
    There are two major advantages of Haskell modules. One is we can structure our scripts into bite-sized chunks, separating out little groups of related functions intoseparate modules. The other advantage is that the functions in a compiled module are much faster to evaluate because their definitions are compiled into machinespecific code, leading to a much slicker reduction process. GHCi is an interpreter rather than a compiler; it evaluates internal forms of expression that are much closer to the source language of Haskell.
2.7 Haskell layout
    The examples of do -notation used braces ( { and } ) and semicolons; these are examples of explicit layout . Braces and semicolons are used only to control layout and have no meaning as part of the language of Haskell expressions. We can use them in other places too:
    roots :: (Float,Float,Float) -> (Float,Float)
    roots (a,b,c)
    | a == 0 = error "not quadratic"
    | disc < 0 = error "complex roots"
    | otherwise = ((-b-r)/e,

Similar Books

The Mahabharata Secret

Christopher C Doyle

Hide in Time

Anna Faversham