Upcoming SlideShare
×

Like this document? Why not share!

on Dec 07, 2011

• 3,890 views

Views

Total Views
3,890
Views on SlideShare
3,890
Embed Views
0

Likes
3
36
0

No embeds

Report content

• Comment goes here.
Are you sure you want to

• Real World Haskell 29.09.08 14:29 Real World Haskell by Bryan OSullivan, Don Stewart, and John Goerzen Why functional programming? Why Haskell? 1. Getting started 2. Types and functions 3. Defining types, streamlining functions 4. Functional programming 5. Writing a library: working with JSON data 6. Using typeclasses 7. Input and output 8. Efficient file processing, regular expressions, and file name matching 9. I/O case study: a library for searching the filesystem 10. Code case study: parsing a binary data format 11. Testing and quality assurance 12. Barcode recognition 13. Data structures 14. Monads 15. Programming with monads 16. The Parsec parsing library 17. The foreign function interface 18. Monad transformers 19. Error handling 20. Systems programming 21. Working with databases 22. Web client programming 23. GUI programming 24. Basic concurrent and parallel programming 25. Profiling and tuning for performance 26. Advanced library design: building a Bloom filterhttp://book.realworldhaskell.org/read/ Seite 1 von 2
• Chapter 3. Defining Types, Streamlining Functions 29.09.08 14:03 We could continue in this fashion indefinitely, creating ever longer Cons chains, each with a single Nil at the end. 2 comments Is List an acceptable list? We can easily prove to ourselves that our List a type has the same shape as the built-in list type [a]. To do this, we write a function that takes any value of type [a], and produces a value of type List a. 2 comments -- file: ch03/ListADT.hs fromList (x:xs) = Cons x (fromList xs) fromList [] = Nil No comments By inspection, this clearly substitutes a Cons for every (:), and a Nil for each []. This covers both of the built-in list types constructors. The two types are isomorphic; they have the same shape. 2 comments ghci> fromList "durian" Cons d (Cons u (Cons r (Cons i (Cons a (Cons n Nil))))) ghci> fromList [Just True, Nothing, Just False] Cons (Just True) (Cons Nothing (Cons (Just False) Nil)) 2 comments For a third example of what a recursive type is, here is a definition of a binary tree type. 2 comments -- file: ch03/Tree.hs data Tree a = Node a (Tree a) (Tree a) | Empty deriving (Show) 1 comment A binary tree is either a node with two children, which are themselves binary trees, or an empty value. No comments This time, lets search for insight by comparing our definition with one from a more familiar language. Heres a similar class definition in Java. 1 comment class Tree<A> { A value; Tree<A> left; Tree<A> right; public Tree(A v, Tree<A> l, Tree<A> r) { value = v; left = l; right = r; } } 1 comment The one significant difference is that Java lets us use the special value null anywhere to indicate “nothing”, so we can use null to indicate that a node is missing a left or right child. Heres a small function that constructs a tree with two leaves (a leaf, by convention, has no children). Nohttp://book.realworldhaskell.org/read/defining-types-streamlining-functions.html Seite 18 von 29
• Chapter 4. Functional programming 29.09.08 14:04 predicate as its first argument; all returns True if that predicate succeeds on every element of the list, while any returns True if the predicate succeeds on at least one element of the list. 4 comments ghci> :type all all :: (a -> Bool) -> [a] -> Bool ghci> all odd [1,3,5] True ghci> all odd [3,1,4,1,5,9,2,6,5] False ghci> all odd [] True ghci> :type any any :: (a -> Bool) -> [a] -> Bool ghci> any even [3,1,4,1,5,9,2,6,5] True ghci> any even [] False No comments Working with sublists The take function, which we already met in the section called “Function application”, returns a sublist consisting of the first k elements from a list. Its converse, drop, drops k elements from the start of the list. 2 comments ghci> :type take take :: Int -> [a] -> [a] ghci> take 3 "foobar" "foo" ghci> take 2 [1] [1] ghci> :type drop drop :: Int -> [a] -> [a] ghci> drop 3 "xyzzy" "zy" ghci> drop 1 [] [] No comments The splitAt function combines the functions of take and drop, returning a pair of the input list, split at the given index. 2 comments ghci> :type splitAt splitAt :: Int -> [a] -> ([a], [a]) ghci> splitAt 3 "foobar" ("foo","bar") No comments The takeWhile and dropWhile functions take predicates: takeWhile takes elements from the beginning of a list as long as the predicate returns True, while dropWhile drops elements from the list as long as the predicate returns True. 1 comment ghci> :type takeWhile takeWhile :: (a -> Bool) -> [a] -> [a] ghci> takeWhile odd [1,3,5,6,8,9,11] [1,3,5] ghci> :type dropWhile dropWhile :: (a -> Bool) -> [a] -> [a] ghci> dropWhile even [2,4,6,7,9,10,12] [7,9,10,12]http://book.realworldhaskell.org/read/functional-programming.html Seite 11 von 40
• Chapter 5. Writing a library: working with JSON data 29.09.08 14:05 Want to stay up to date? Subscribe to the comment feed for this chapter, or the entire book. Copyright 2007, 2008 Bryan OSullivan, Don Stewart, and John Goerzen. This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 License. Icons by Paul Davey aka Mattahan. Prev Next Chapter 4. Functional programming Home Chapter 6. Using Typeclasseshttp://book.realworldhaskell.org/read/writing-a-library-working-with-json-data.html Seite 23 von 23
• Chapter 6. Using Typeclasses 29.09.08 14:06 Lets begin our discussion of the typeclasses surrounding numeric types with an examination of the types themselves. Table 6.1, “Selected Numeric Types” describes the most commonly-used numeric types in Haskell. Note that there are also many more numeric types available for specific purposes such as interfacing to C. 5 comments Table 6.1. Selected Numeric Types Type Description Double Double-precision floating point. A common choice for floating-point data. Float Single-precision floating point. Often used when interfacing with C. Int Fixed-precision signed integer; minimum range [-2^29..2^29-1]. Commonly used. Int8 8-bit signed integer Int16 16-bit signed integer Int32 32-bit signed integer Int64 64-bit signed integer Integer Arbitrary-precision signed integer; range limited only by machine resources. Commonly used. Rational Arbitrary-precision rational numbers. Stored as a ratio of two Integers. Word Fixed-precision unsigned integer; storage size same as Int Word8 8-bit unsigned integer Word16 16-bit unsigned integer Word32 32-bit unsigned integer Word64 64-bit unsigned integer These are quite a few different numeric types. There are some operations, such as addition, that work with all of them. There are others, such as asin, that only apply to floating-point types. Table 6.2, “Selected Numeric Functions and Constants” summarizes the different functions that operate on numeric types, and Table 6.3, “Typeclass Instances for Numeric Types” matches the types with their respective typeclasses. As you read that table, keep in mind that Haskell operators are just functions: you can say either (+) 2 3 or 2 + 3 with the same result. By convention, when referring to an operator as a function, it is written in parenthesis as seen in this table. 6 comments Table 6.2. Selected Numeric Functions and Constants Item Type Module Description (+) Num a => a -> a -> a Prelude Addition (-) Num a => a -> a -> a Prelude Subtraction (*) Num a => a -> a -> a Prelude Multiplication Fractional a => a -> a - (/) > a Prelude Fractional division Floating a => a -> a -> (**) a Prelude Raise to the power of (^) (Num a, Integral b) => a Prelude Raise a number to a non-negative, integral -> b -> a power (^^) (Fractional a, Integral Prelude Raise a fractional number to any integral b) => a -> b -> a power Integral a => a -> a -> (%) Ratio a Data.Ratio Ratio composition (.&.) Bits a => a -> a -> a Data.Bits Bitwise and (.|.) Bits a => a -> a -> a Data.Bits Bitwise or abs Num a => a -> a Prelude Absolute valuehttp://book.realworldhaskell.org/read/using-typeclasses.html Seite 10 von 27
• Chapter 6. Using Typeclasses 29.09.08 14:06 approxRational RealFrac a => a -> a -> Data.Ratio Approximate rational composition based on Rational fractional numerators and denominators cos Floating a => a -> a Prelude Cosine. Also provided are acos, cosh, and acosh, with the same type. div Integral a => a -> a -> Prelude Integer division always truncated down; see a also quot fromInteger Num a => Integer -> a Prelude Conversion from an Integer to any numeric type fromIntegral (Integral a, Num b) => a Prelude More general conversion from any Integral to -> b any numeric type Fractional a => Rational fromRational -> a Prelude Conversion from a Rational. May be lossy. log Floating a => a -> a Prelude Natural logarithm Floating a => a -> a -> logBase a Prelude Log with explicit base maxBound Bounded a => a Prelude The maximum value of a bounded type minBound Bounded a => a Prelude The minimum value of a bounded type Integral a => a -> a -> mod a Prelude Integer modulus pi Floating a => a Prelude Mathematical constant pi quot Integral a => a -> a -> Prelude Integer division; fractional part of quotient a truncated towards zero recip Fractional a => a -> a Prelude Reciprocal Integral a => a -> a -> rem a Prelude Remainder of integer division (RealFrac a, Integral b) round => a -> b Prelude Rounds to nearest integer shift Bits a => a -> Int -> a Bits Shift left by the specified number of bits, which may be negative for a right shift. sin Floating a => a -> a Prelude Sine. Also provided are asin, sinh, and asinh, with the same type. sqrt Floating a => a -> a Prelude Square root tan Floating a => a -> a Prelude Tangent. Also provided are atan, tanh, and atanh, with the same type. Integral a => a -> toInteger Integer Prelude Convert any Integral to an Integer toRational Real a => a -> Rational Prelude Convert losslessly to Rational (RealFrac a, Integral b) truncate => a -> b Prelude Truncates number towards zero xor Bits a => a -> a -> a Data.Bits Bitwise exclusive or Table 6.3. Typeclass Instances for Numeric Types Type Bits Bounded Floating Fractional Integral Num Real RealFrac Double X X X X X Float X X X X X Int X X X X X Int16 X X X X X Int32 X X X X X Int64 X X X X X Integer X X X X Rational or any Ratio X X X Xhttp://book.realworldhaskell.org/read/using-typeclasses.html Seite 11 von 27
• Chapter 7. I/O 29.09.08 14:07 There are many other functions in System.Directory for doing things such as creating and removing directories, finding lists of files in directories, and testing for file existence. These are discussed in the section called “Directory and File Information”. No comments Temporary Files Programmers frequently need temporary files. These files may be used to store large amounts of data needed for computations, data to be used by other programs, or any number of other uses. No comments While you could craft a way to manually open files with unique names, the details of doing this in a secure way differ from platform to platform. Haskell provides a convenient function called openTempFile (and a corresponding openBinaryTempFile) to handle the difficult bits for you. No comments openTempFile takes two parameters: the directory in which to create the file, and a "template" for naming the file. The directory could simply be "." for the current working directory. Or you could use System.Directory.getTemporaryDirectory to find the best place for temporary files on a given machine. The template is used as the basis for the file name; it will have some random characters added to it to ensure that the result is truly unique. It guarantees that it will be working on a unique filename, in fact. No comments The return type of openTempFile is IO (FilePath, Handle). The first part of the tuple is the name of the file created, and the second is a Handle opened in ReadWriteMode over that file. When youre done with the file, youll want to hClose it and then call removeFile to delete it. See the following example for a sample function to use. 1 comment Extended Example: Functional I/O and Temporary Files Heres a larger example that puts together some concepts from this chapter, from some earlier chapters, and a few you havent seen yet. Take a look at the program and see if you can figure out what it does and how it works. No comments -- file: ch07/tempfile.hs import System.IO import System.Directory(getTemporaryDirectory, removeFile) import System.IO.Error(catch) import Control.Exception(finally) -- The main entry point. Work with a temp file in myAction. main :: IO () main = withTempFile "mytemp.txt" myAction {- The guts of the program. Called with the path and handle of a temporary file. When this function exits, that file will be closed and deleted because myAction was called from withTempFile. -} myAction :: FilePath -> Handle -> IO () myAction tempname temph = do -- Start by displaying a greeting on the terminal putStrLn "Welcome to tempfile.hs" putStrLn \$ "I have a temporary file at " ++ tempname -- Lets see what the initial position is pos <- hTell temph putStrLn \$ "My initial position is " ++ show pos -- Now, write some data to the temporary file let tempdata = show [1..10] putStrLn \$ "Writing one line containing " ++ show (length tempdata) ++ " bytes: " ++ tempdata hPutStrLn temph tempdatahttp://book.realworldhaskell.org/read/io.html Seite 9 von 23
• Chapter 7. I/O 29.09.08 14:07 -- Get our new position. This doesnt actually modify pos -- in memory, but makes the name "pos" correspond to a different -- value for the remainder of the "do" block. pos <- hTell temph putStrLn \$ "After writing, my new position is " ++ show pos -- Seek to the beginning of the file and display it putStrLn \$ "The file content is: " hSeek temph AbsoluteSeek 0 -- hGetContents performs a lazy read of the entire file c <- hGetContents temph -- Copy the file byte-for-byte to stdout, followed by n putStrLn c -- Lets also display it as a Haskell literal putStrLn \$ "Which could be expressed as this Haskell literal:" print c {- This function takes two parameters: a filename pattern and another function. It will create a temporary file, and pass the name and Handle of that file to the given function. The temporary file is created with openTempFile. The directory is the one indicated by getTemporaryDirectory, or, if the system has no notion of a temporary directory, "." is used. The given pattern is passed to openTempFile. After the given function terminates, even if it terminates due to an exception, the Handle is closed and the file is deleted. -} withTempFile :: String -> (FilePath -> Handle -> IO a) -> IO a withTempFile pattern func = do -- The library ref says that getTemporaryDirectory may raise on -- exception on systems that have no notion of a temporary directory. -- So, we run getTemporaryDirectory under catch. catch takes -- two functions: one to run, and a different one to run if the -- first raised an exception. If getTemporaryDirectory raised an -- exception, just use "." (the current working directory). tempdir <- catch (getTemporaryDirectory) (_ -> return ".") (tempfile, temph) <- openTempFile tempdir pattern -- Call (func tempfile temph) to perform the action on the temporary -- file. finally takes two actions. The first is the action to run. -- The second is an action to run after the first, regardless of -- whether the first action raised an exception. This way, we ensure -- the temporary file is always deleted. The return value from finally -- is the first actions return value. finally (func tempfile temph) (do hClose temph removeFile tempfile) 6 comments Lets start looking at this program from the end. The withTempFile function demonstrates that Haskell doesnt forget its functional nature when I/O is introduced. This function takes a String and another function. The function passed to withTempFile is invoked with the name and Handle of a temporary file. When that function exits, the temporary file is closed and deleted. So even when dealing with I/O, we can still find the idiom of passing functions as parameters to be convenient. Lisp programmers might find our withTempFile function similar to Lisps with-open-file function. 1 comment There is some exception handling going on to make the program more robust in the face of errors. You normally want the temporary files to be deleted after processing completes, even if something went wrong. So we make sure that happens. For more on exception handling, see Chapter 19, Error handling. 1 comment Lets return to the start of the program. main is defined simply as withTempFile "mytemp.txt" myAction. myAction, then, will be invoked with the name and Handle of the temporary file. No commentshttp://book.realworldhaskell.org/read/io.html Seite 10 von 23
• Chapter 8. Efficient file processing, regular expressions, and file name matching 29.09.08 14:07 ghci> pack "foo" =~ "bar" :: Bool False ghci> "foo" =~ pack "bar" :: Int 0 ghci> pack "foo" =~ pack "o" :: [(Int, Int)] <interactive>:1:0: No instance for (RegexContext Regex ByteString [(Int, Int)]) arising from a use of `=~ at <interactive>:1:0-21 Possible fix: add an instance declaration for (RegexContext Regex ByteString [(Int, Int)]) In the expression: pack "foo" =~ pack "o" :: [(Int, Int)] In the definition of `it: it = pack "foo" =~ pack "o" :: [(Int, Int)] 4 comments However, we need to be aware that if we want a string value in the result of a match, the text were matching against must be the same type of string. Lets see what this means in practice. No comments ghci> pack "good food" =~ ".ood" :: [ByteString] <interactive>:1:0: No instance for (RegexContext Regex ByteString [ByteString]) arising from a use of `=~ at <interactive>:1:0-25 Possible fix: add an instance declaration for (RegexContext Regex ByteString [ByteString]) In the expression: pack "good food" =~ ".ood" :: [ByteString] In the definition of `it: it = pack "good food" =~ ".ood" :: [ByteString] 5 comments In the above example, weve used the pack to turn a String into a ByteString. The type checker accepts this because ByteString appears in the result type. But if we try getting a String out, that wont work. 1 comment ghci> "good food" =~ ".ood" :: [ByteString] <interactive>:1:0: No instance for (RegexContext Regex [Char] [ByteString]) arising from a use of `=~ at <interactive>:1:0-20 Possible fix: add an instance declaration for (RegexContext Regex [Char] [ByteString]) In the expression: "good food" =~ ".ood" :: [ByteString] In the definition of `it: it = "good food" =~ ".ood" :: [ByteString] 1 comment We can easily fix this problem by making the string types of the left hand side and the result match once again. No comments ghci> "good food" =~ ".ood" :: [String] <interactive>:1:0: No instance for (RegexContext Regex [Char] [String]) arising from a use of `=~ at <interactive>:1:0-20 Possible fix: add an instance declaration for (RegexContext Regex [Char] [String]) In the expression: "good food" =~ ".ood" :: [String] In the definition of `it: it = "good food" =~ ".ood" :: [String]http://book.realworldhaskell.org/read/efficient-file-processing-regular-expressions-and-file-name-matching.html Seite 9 von 20