packages feed

lambdabot-4.0: Plugin/Lambda/ListTerm.hs

module Plugin.Lambda.ListTerm where

import Plugin.Lambda.LangPack
import Plugin.Lambda.LambdaTerm

import Data.Map (Map)

import Data.Dynamic
import Control.Monad.Error
import Control.Monad.Reader

data ListTerm term
   = Nil
   | Character !Char
   | Head term
   | Tail term
   | Null term
   | Cons term term
   | Append term term

prjL :: (MonadError String m, 
         Typeable (m Dynamic)) => m Dynamic -> m (m Dynamic, m Dynamic)
prjL = prj'

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

prjC :: (MonadError String m) => m Dynamic -> m Char
prjC = prj'

phiList :: (MonadError String m,
            MonadReader (Map String (m Dynamic)) m,
            Typeable (m Dynamic)) => ListTerm (m Dynamic) -> m Dynamic
phiList Nil = return $ inj ()
phiList (Character c) = return $ inj c
-- TODO: double evaluation of l
phiList (Head l) = do b <- isNull l; if b then throwError "head of empty list"
                                          else prjL l >>= fst
phiList (Tail l) = do b <- isNull l; if b then throwError "tail of empty list"
                                          else prjL l >>= snd
phiList (Null l) = do b <- isNull l; if b then return (inj True)
                                          else do prjL l; return (inj False)
-- TODO: this is call-by-name, not call-by-need
phiList (Cons l r) = do env <- ask; return $ inj (inEnv env l,inEnv env r)
phiList (Append l r) = do env <- ask
                          foldList (\x y -> return $ inj (x,y)) 
                                   (inEnv env r) 
                                   (inEnv env l)

isNull :: (Monad m) => m Dynamic -> m Bool
isNull m = do d <- m; case (fromDynamic d :: Maybe ()) of
                         Just _  -> return True
                         Nothing -> return False

isCharacter :: (Monad m) => m Dynamic -> m Bool
isCharacter m = do d <- m; case (fromDynamic d :: Maybe Char) of
                              Just _  -> return True
                              Nothing -> return False

foldList :: (MonadError String m, Typeable (m Dynamic)) => 
            (m Dynamic -> m a -> m a) -> 
                    m a -> m Dynamic  -> m a
foldList c n l = do
    b <- isNull l
    if b then n
         else do (f,r) <- prjL l
                 c f $ foldList c n r

instance Functor ListTerm where
    fmap _ Nil = Nil
    fmap _ (Character c) = Character c
    fmap f (Head l) = Head (f l)
    fmap f (Tail l) = Tail (f l)
    fmap f (Null l) = Null (f l)
    fmap f (Cons l r) = Cons (f l) (f r)
    fmap f (Append l r) = Append (f l) (f r)