[Write more about glob matching. Start section using IO monad. Bryan O'Sullivan **20070614053203] { hunk ./en/Makefile 15 + ch07/glob-to-regexp/Glob.hs \ hunk ./en/ch07-globs-and-regexps.xml 21 - to use regular expressions in Haskell. We'll then write an - interpreter for the pattern language directly, so that we can - avoid the regular expression library. Finally, we'll talk about - how to use Haskell's standard directory listing functions with - this library. Along the way, we'll talk a little about writing - portable code in Haskell. + to use regular expressions in Haskell. Next, we'll talk about how + to use Haskell's standard directory listing functions with this + library. We'll then write an interpreter for the pattern language + directly, so that we can avoid the regular expression library. + Along the way, we'll talk a little about writing portable code in + Haskell. hunk ./en/ch07-globs-and-regexps.xml 34 - pattern. Although Haskell's standard library generally has good - system programming facilities, it doesn't provide - these kinds of pattern matching functions. We'll take this as - an opportunity to develop our own. + pattern. (In other languages, this function is often named + fnmatch.) Although Haskell's standard + library generally has good system programming + facilities, it doesn't provide these kinds of pattern matching + functions. We'll take this as an opportunity to develop our + own. hunk ./en/ch07-globs-and-regexps.xml 402 - These results might seem trivial, but we have received - immediate feedback on two fronts: our code passes the scrutiny - of the typechecker, and it produces sensible-looking results. - Monkeying around with code in the interpreter early and often is - consistently worthwhile. + These few lines of interaction might look trivial, but we + have received immediate feedback on two fronts: our code passes + the daunting scrutiny of Haskell's typechecker, and it produces + sensible-looking results. Monkeying around with code in the + interpreter early and often is consistently worthwhile. hunk ./en/ch07-globs-and-regexps.xml 452 + Now that we've finished defining + globToRegex and its helpers, let's load it + into &ghci; and try it out. + + &glob-regexp.ghci:real; + + Sure enough, that looks like a reasonable regexp. Can we + use it to match against a string? + + &glob-regexp.ghci:matches; + + It works! Now let's play around a little with &ghci;. We + can create a temporary definition for + fnmatch and try it out. (This is another + example of how &ghci; is great for exploratory + programming.) + + &glob-regexp.ghci:fnmatch; + + The name fnmatch doesn't + really have the Haskell nature, though. The + typical Haskell style is for functions to have descriptive, + camel cased names. In our library, we'll give this function the + name matchesGlob. + + &GlobRegex.hs:matchesGlob; + hunk ./en/ch07-globs-and-regexps.xml 482 - Writing lazy functions + An important aside: writing lazy functions hunk ./en/ch07-globs-and-regexps.xml 485 - globToRegex function is one that we'd + globToRegex' function is one that we'd hunk ./en/ch07-globs-and-regexps.xml 625 + + + Making use of our pattern matcher + + It's all very well to have a function that can match + glob patterns, but we'd like to be able to put this to practical + use. On Unix-like systems, the glob + function returns the names of all files and directories that + match a given glob pattern. + + Since directories and files live in the real + world, our globbing function will have to have + IO in its result type. Following the + Haskell norm of descriptive naming, we'll call our function + namesMatching. + + &Glob.hs:type; + + + hunk ./examples/ch07/glob-regexp.ghci 11 +--# real + +:load glob-to-regexp/GlobRegex.hs +:module +Text.Regex.Posix + +globToRegex "f??.c" + +--# matches + +"foo.c" =~ globToRegex "f??.c" :: Bool +"test.c" =~ globToRegex "t[ea]s*" :: Bool +"taste.txt" =~ globToRegex "t[ea]s*" :: Bool + +--# fnmatch + +let fnmatch pat name = name =~ globToRegex pat :: Bool +:type fnmatch + +fnmatch "myname" "d*" + addfile ./examples/ch07/glob-to-regexp/Glob.hs hunk ./examples/ch07/glob-to-regexp/Glob.hs 1 +module Glob (namesMatching) where + +import GlobRegex (matchesGlob) + +{-- snippet type --} +namesMatching :: String -> IO [FilePath] +{-- /snippet type --} + +namesMatching pat = undefined + +isMagical :: String -> Bool + +isMagical = any (`elem` "[*?") hunk ./examples/ch07/glob-to-regexp/GlobRegex.hs 1 -{-- snippet header --} hunk ./examples/ch07/glob-to-regexp/GlobRegex.hs 4 - , matchesPattern + , matchesGlob hunk ./examples/ch07/glob-to-regexp/GlobRegex.hs 6 -{-- /snippet header --} hunk ./examples/ch07/glob-to-regexp/GlobRegex.hs 7 -{-- snippet imports --} -import System.FilePath (pathSeparator) hunk ./examples/ch07/glob-to-regexp/GlobRegex.hs 8 -{-- /snippet imports --} hunk ./examples/ch07/glob-to-regexp/GlobRegex.hs 51 -matchesPattern :: String -> String -> Bool -name `matchesPattern` pat = name =~ globToRegex pat +{-- snippet matchesGlob --} +matchesGlob :: FilePath -> String -> Bool +name `matchesGlob` pat = name =~ globToRegex pat +{-- /snippet matchesGlob --} }