--
import Monad(MonadPlus(..)) import Char(isAlphaNum) import Array(Array,array,(!),ixmap,elems) fib :: Integer -> Integer fib 0 = 1 fib 1 = 1 fib n = fib (n-1) + fib (n-2) {- Main> fib 25 121393 (4334712 reductions, 7091332 cells, 30 garbage collections) takes about 4 seconds on my machine -} fix f = f (fix f) g fib 0 = 1 g fib 1 = 1 g fib n = fib (n-1) + fib (n-2) fib1 = fix g fib2 :: Integer -> Integer fib2 z = f z where table = array (0,z) [ (i, f i) | i <- range (0,z) ] f 0 = 1 f 1 = 1 f n = (table ! (n-1)) + (table ! (n-2)) memo :: Ix a => (a,a) -> ((a -> b) -> a -> b) -> a -> b memo bounds g = f where arrayF = array bounds [ (n, g f n) | n <- range bounds ] f x = arrayF ! x fib3 n = memo (0,n) g n fact = memo (0,100) g where g fact n = if n==0 then 1 else n * fact (n-1) --=================================================================== -- Between these lines is a parsing library {--------------------------------------------------------------------- A GOFER LIBRARY OF MONADIC PARSER COMBINATORS 29th November 1996 (modified by Erik Meijer for use with Gofer) Graham Hutton Erik Meijer Philip Wadler University of Nottingham University of Utrecht Bell Laboratories This Haskell 1.3 library is derived from our article "Monadic Parsing in Haskell". The library also includes a few extra combinators that were not discussed in the article for reasons of space: o force (used to make "many" deliver results lazily); o digit, lower, upper, letter, alphanum (useful parsers); o ident, nat, int (useful token parsers); o comment (a parser for single-line Haskell comments). -- This library was modifed by Tim Sheard to work with Haskell 98 (2/25/2003) ---------------------------------------------------------------------} infixr 5 +++ -- Monad of parsers: ------------------------------------------------- data Parser a = Parser (String -> [(a,String)]) instance Monad Parser where return v = Parser (\inp -> [(v,inp)]) p >>= f = Parser (\inp -> concat [applyP (f v) out | (v,out) <- applyP p inp]) instance MonadPlus Parser where mzero = Parser (\inp -> []) mplus (Parser p) (Parser q) = Parser(\inp -> p inp ++ q inp) instance Functor Parser -- Other parsing primitives: ----------------------------------------- applyP :: Parser a -> String -> [(a,String)] applyP (Parser p) = p item :: Parser Char item = Parser (\inp -> case inp of "" -> [] (x:xs) -> [(x,xs)]) sat :: (Char -> Bool) -> Parser Char sat p = do {x <- item; if (p x) then return x else mzero} -- Efficiency improving combinators: --------------------------------- force :: Parser a -> Parser a force p = Parser (\inp -> let x = applyP p inp in (fst (head x), snd (head x)) : tail x) (+++) :: Parser a -> Parser a -> Parser a p +++ q = Parser(\inp -> case applyP (p `mplus` q) inp of [] -> [] (x:xs) -> [x]) -- Recursion combinators: -------------------------------------------- string :: String -> Parser String string "" = return "" string (x:xs) = do char x; string xs return (x:xs) many :: Parser a -> Parser [a] many p = force (many1 p +++ return []) many1 :: Parser a -> Parser [a] many1 p = do x <- p xs <- many p return (x:xs) sepby :: Parser a -> Parser b -> Parser [a] p `sepby` sep = (p `sepby1` sep) +++ return [] sepby1 :: Parser a -> Parser b -> Parser [a] p `sepby1` sep = do x <- p xs <- many (do {sep; p}) return (x:xs) chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a chainl p op v = (p `chainl1` op) +++ return v chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a p `chainl1` op = do x <- p rest x where rest x = do {f <- op; y <- p; rest (f x y)} +++ return x -- Useful parsers: --------------------------------------------------- char :: Char -> Parser Char char x = sat (x ==) digit :: Parser Int digit = do x <- sat isDigit return (ord x - ord '0') lower :: Parser Char lower = sat isLower upper :: Parser Char upper = sat isUpper letter :: Parser Char letter = sat isAlpha alphanum :: Parser Char alphanum = sat isAlphaNum symb :: String -> Parser String symb xs = token (string xs) ident :: [String] -> Parser String ident ks = do x <- token identifier if (not (elem x ks)) then return x else mzero identifier :: Parser String identifier = do x <- lower xs <- many alphanum return (x:xs) nat :: Parser Int nat = token natural natural :: Parser Int natural = digit `chainl1` return (\m n -> 10*m + n) int :: Parser Int int = token integer integer :: Parser Int integer = (do char '-' n <- natural return (-n)) +++ nat -- Lexical combinators: ---------------------------------------------- spaceP :: Parser () spaceP = do {many1 (sat isSpace); return ()} comment :: Parser () comment = do string "--" many (sat p) return () where p x = x /= '\n' junk :: Parser () junk = do {many (spaceP +++ comment); return ()} token :: Parser a -> Parser a token p = do {v <- p; junk; return v} parse :: Parser a -> String -> [(a,String)] parse p = applyP (do {junk; p}) -- Example parser for arithmetic expressions: ------------------------ data Term = Add Term Term | Sub Term Term | Mult Term Term | Div Term Term | Const Int expr :: Parser Term addop :: Parser (Term -> Term -> Term) mulop :: Parser (Term -> Term -> Term) expr = term `chainl1` addop term = factor `chainl1` mulop factor = (do n <- token digit return (Const n)) +++ (do symb "(" n <- expr symb ")" return n) addop = do {symb "+"; return Add} +++ do {symb "-"; return Sub} mulop = do {symb "*"; return Mult} +++ do {symb "/"; return Div} --=================================================================== ex1 = parse item "abc" ex2 = parse (sat isSpace) "abc" ex3 = parse expr "4 + 5 - 2" --==================================================================== type Subword = (Int,Int) newtype P a = P (Array Int Char -> Subword -> [a]) unP (P z) = z emptyP :: P () emptyP = P f where f z (i,j) = [() | i == j] notchar :: Char -> P Char notchar s = P f where f z (i,j) = [z!j | i+1 == j, z!j /= s] charP :: Char -> P Char charP c = P f where f z (i,j) = [c | i+1 == j, z!j == c] anychar :: P Char anychar = P f where f z (i,j) = [z!j | i+1 == j] anystring :: P(Int,Int) anystring = P f where f z (i,j) = [(i,j) | i <= j] symbol :: String -> P (Int,Int) symbol s = P f where f z (i,j) = if j-i == length s then [(i,j)| and [z!(i+k) == s!!(k-1) | k <-[1..(j-i)]]] else [] infixr 6 ||| (|||) :: P b -> P b -> P b (|||) (P r) (P q) = P f where f z (i,j) = r z (i,j) ++ q z (i,j) infix 8 <<< (<<<) :: (b -> c) -> P b -> P c (<<<) f (P q) = P h where h z (i,j) = map f (q z (i,j)) infixl 7 ~~~ (~~~) :: P(b -> c) -> P b -> P c (~~~) (P r) (P q) = P f where f z (i,j) = [f y | k <- [i..j], f <- r z (i,k), y <- q z (k,j)] infix 5 ... (...) :: P b -> ([b] -> [b]) -> P b (...) (P r) h = P g where g z (i,j) = h (r z (i,j)) type Filter = (Int, Int) -> Bool withX :: P b -> Filter -> P b withX (P q) c = P g where g z (i,j) = if c (i,j) then q z (i,j) else [] run :: String -> P b -> [b] run s (P ax) = ax (s2a s) (0,length s) s2a s = (array bounds (zip [1..] s)) where bounds = (1,length s) instance Monad P where return x = P(\ z (i,j) -> if i==j then [x] else []) (>>=) (P f) g = P h where h z (i,j) = concat[ unP (g a) z (k,j) | k <- [i..j] , a <- f z (i,k)] p1 = do { symbol "tim"; c <- anychar; symbol "tom"; return c} ex4 = run "tim5tom" p1 ex5 = run "timtom" p1 --