import Data.Char
import Data.Maybe
import Control.Monad
import Control.Monad.State

-- 構文解析器結合子 ----------------------------------------------------

failure :: Parser t a
failure = mzero

succeed :: a -> Parser t a
succeed = return

item :: Parser t t
item = do { (x:xs) <- get
          ; put xs
          ; return x
          }

sat :: (t -> Bool) -> Parser t t
sat p = do { x <- item
           ; if p x then return x else failure
           }

alt :: Parser t a -> Parser t a -> Parser t a
alt = mplus

many :: Parser t a -> Parser t [a]
many p = many1 p `alt` return []

many1 :: Parser t a -> Parser t [a]
many1 p = do { x  <- p
            ; xs <- many p
            ; return (x:xs)
            }

-- 計算木の再構成 ------------------------------------------------------

data Term = Val Char | App Char Term Term

instance Show Term where
  show (Val c)     = [c]
  show (App o l r) = "(" ++ show l ++ [o] ++ show r ++ ")"


pterm, papp, pval :: Parser Char Term
pterm = papp `alt` pval

papp = do { sat ('('==)
          ; l <- pterm
          ; o <- pbop
          ; r <- pterm
          ; sat (')'==)
          ; return (App o l r)
          }

pval = do { c <- sat (`elem` "0123456789")
          ; return (Val c)
          }

pbop :: Parser Char Char
pbop = do { o <- sat (`elem` "+-*/")
          ; return o 
          }

type Rat = (Int,Int)

eval :: Term -> Rat
eval (Val x)     = ctor x
eval (App o l r) = (ctoo o) (eval l) (eval r)

ctor :: Char -> Rat
ctor x = (ord x - ord '0',1)

ctoo :: Char -> (Rat -> Rat -> Rat)
ctoo '+' (x,y) (z,w) = (x*w+z*y,y*w)
ctoo '-' (x,y) (z,w) = (x*w-z*y,y*w)
ctoo '*' (x,y) (z,w) = (x*z,y*w)
ctoo '/' (x,y) (z,w) = if z == 0 then (0,0) else (x*w,y*z)

-- List 版パーザと Maybe 版パーザ

type Parser t a = StateT [t] [] a        -- List 版
instance Read Term where
  readsPrec _ = runParser pterm

{-
type Parser t a = StateT [t] Maybe a     -- Maybe 版
instance Read Term where
  readsPrec _ = maybeToList . runParser pterm
-}

runParser = runStateT

-- List版とMaybe版の違いを見るための例 ---------------------------------

char :: Char -> Parser Char Char
char c = sat (c ==)

pS = do { a   <- pa
        ; bc  <- pB
        ; d   <- pd
        ; return ([a]++bc++[d])
        }

pB =       (do { b <- pb; return [b] })
     `alt` (do { b <- pb; c <- pc; return ([b]++[c]) })

pa = char 'a'
pb = char 'b'
pc = char 'c'
pd = char 'd'

