--
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



--