packages feed

lambdabot-4.0: Plugin/Lambda/RelTerm.hs

module Plugin.Lambda.RelTerm where

import Plugin.Lambda.LangPack
import Plugin.Lambda.ArithTerm (prjI)
import Plugin.Lambda.ListTerm (prjC,prjL,prjN)

import Data.Dynamic
import Control.Monad.Error

data RelTerm term
   = Boolean !Bool
   | And term term
   | Or term term
   | Not term
   | Equal term term
   | NotEqual term term
   | LessThan term term
   | GreaterThan term term
   | LessThanOrEqual term term
   | GreaterThanOrEqual term term
   | IfE term term term

prjB :: (MonadError String m) => m Dynamic -> m Bool
prjB = prj'

doOp :: (MonadError String m, Typeable (m Dynamic)) => (forall a.Ord a => a -> a -> Bool) -> 
            m Dynamic -> m Dynamic -> m Dynamic
doOp op l r 
    = catchError (do l' <- prjI l; r' <- prjI r; return $ inj (l' `op` r'))
       (\_ -> catchError (do l' <- prjC l; r' <- prjC r; return $ inj (l' `op` r'))
        (\_ -> catchError (do l' <- prjB l; r' <- prjB r; return $ inj (l' `op` r'))
         (\_ -> catchError (do l' <- prjN l; r' <- prjN r; return $ inj (l' `op` r'))
          (\_ -> catchError (do _ <- prjL l; _ <- prjN r; return $ inj False)
           (\_ -> catchError (do _ <- prjN l; _ <- prjL r; return $ inj False)
            (\_ -> catchError (do (a,b) <- prjL l
                                  (x,y) <- prjL r
                                  s <- prjB $ doOp op a x
                                  t <- prjB $ doOp op b y
                                  return $ inj (s && t))
                   throwError))))))

phiRel :: (MonadError String m, Typeable (m Dynamic)) => RelTerm (m Dynamic) -> m Dynamic
phiRel (Boolean b) = return (inj b)
phiRel (IfE c t e) = do b <- prjB c
                        if b then t else e
phiRel (Equal l r) = doOp (==) l r
phiRel (NotEqual l r) = doOp (/=) l r
phiRel (LessThan l r) = doOp (<) l r
phiRel (GreaterThan l r) = doOp (>) l r
phiRel (LessThanOrEqual l r) = doOp (<=) l r
phiRel (GreaterThanOrEqual l r) = doOp (>=) l r
phiRel (And l r) = do l' <- prjB l; if not l' then return $ inj False else do r' <- prjB r; return $ inj (l' && r')
phiRel (Or l r) = do l' <- prjB l; if l' then return $ inj True else do r' <- prjB r; return $ inj (l' || r')
phiRel (Not x) = do x' <- prjB x; return $ inj (not x')

instance Functor RelTerm where
    fmap f (Not x) = Not (f x)
    fmap f (Or l r) = Or (f l) (f r)
    fmap f (And l r) = And (f l) (f r)
    fmap _ (Boolean b) = (Boolean b)
    fmap f (IfE c t e) = IfE (f c) (f t) (f e)
    fmap f (Equal l r) = Equal (f l) (f r)
    fmap f (NotEqual l r) = NotEqual (f l) (f r)
    fmap f (LessThan l r) = LessThan (f l) (f r)
    fmap f (GreaterThan l r) = GreaterThan (f l) (f r)
    fmap f (LessThanOrEqual l r) = LessThanOrEqual (f l) (f r)
    fmap f (GreaterThanOrEqual l r) = GreaterThanOrEqual (f l) (f r)