[Finish chapter 4, I think. Bryan O'Sullivan **20070828061323] { hunk ./en/ch04-fp.xml 1571 - uses the (.) operator to denote function - composition. + provides the (.) operator to denote + function composition. hunk ./en/ch04-fp.xml 1590 - - + Here's an example drawn from a piece of code I wrote the + day before I started on this section. I wanted to get a list + of C preprocessor definitions from a header file shipped with + libpcap, a popular network packet filtering + library. hunk ./en/ch04-fp.xml 1596 - - Working with data structures: the suffix tree - - A suffix tree is a useful and elegant data structure that - lets us deal efficiently with a fixed body of text or some other - kind of sequence. - + &dlts.hs:dlts; hunk ./en/ch04-fp.xml 1598 - - Typeclasses - FIXME: Introduce type classes. Show how ghci infers types - with constraints. Define some functions that use type class - constraints. Talk about when it's appropriate to write explicit - signatures. - - See also . - + We take an entire file, split it up with + lines, then call foldr step + [] on the result. Since I know, based on the type of + lines, that I'm folding over a list of + strings, the step helper function must + thus operate on individual lines. + + &dlts.hs:step; + + If we match a macro definition, we cons the name of the + macro onto the head of the list we're returning; otherwise, we + do nothing with the list on this invocation. + + We can see heavy use of function composition in the body + of step. While all of these functions + are by now familiar to us, it can take a little practice to + glue together the sequence of types in a chain of compositions + like this. Let's walk through the procedure by hand. + + The first call is to words. + + &dlts.ghci:words; hunk ./en/ch04-fp.xml 1621 - - Example: Data.Map API - FIXME: Small example would be a finite map data structure - API, with a list and tree implementation (different complexity, - same api). Ties together basic types, small functions, top level - functions. class Map m where new :: m k v insert :: k -> v - -> m k v -> m k v lookup :: k -> m k v -> v -- simple, O(n) - data Map1 k v = [(k,v)] -- less simple, O(log n) data Map2 k v = - Node k v (Map2 k v) (Map2 k v) | Empty + We then call the partially applied function drop + 1 on the result of words. hunk ./en/ch04-fp.xml 1624 - + &dlts.ghci:drop1; + + See how naturally partial application fits in here? It's + given us a function that turns a list into another list. + Composing these, we match up the result of + words with the parameter of drop + 1. + + &dlts.ghci:drop1.words; + + Finally, calling head on the result + of drop 1 . words will give us what we want: the + name of the macro we're defining. + + &dlts.ghci:head.drop1.words; + + + Use your head wisely + + After warning against unsafe list functions in , here we are calling + head, one of those unsafe list + functions. What gives? + + In this case, we can reassure ourselves that we're safe + from a runtime failure in the call to + head. The pattern guard in the + definition of step ensures that after + we call words on any string that makes + it past the guard, we'll have a list of at least two + elements, "#define" and some macro beginning + with "DLT_". You can see this in some of the + &ghci; code snippets above. + + This is an example of the kind of reasoning we ought to + do to convince ourselves that our code won't explode when we + call partial functions. Don't forget our earlier + admonition: calling unsafe functions like this requires + care, and can often make our code more fragile in subtle + ways. + + addfile ./examples/ch04/dlts.ghci hunk ./examples/ch04/dlts.ghci 1 +--# words +:type words +words "#define DLT_CHAOS 5" + +--# drop1 +:type drop 1 + +--# drop1.words +:type drop 1 . words +(drop 1 . words) "#define DLT_CHAOS 5" + +--# head.drop1.words +:type head . drop 1 . words +(head . drop 1 . words) "#define DLT_CHAOS 5" addfile ./examples/ch04/dlts.hs hunk ./examples/ch04/dlts.hs 1 +{-- snippet dlts --} +import Data.List (isPrefixOf) + +dlts :: String -> [String] + +dlts = foldr step [] . lines +{-- /snippet dlts --} +{-- snippet step --} + where step l ds + | "#define DLT_" `isPrefixOf` l = (head . drop 1 . words) l : ds + | otherwise = ds +{-- /snippet step --} + }