lambdabot-4.0: Plugin/Lambda/LambdaTerm.hs
module Plugin.Lambda.LambdaTerm where
import Plugin.Lambda.LangPack
import Data.Map (Map)
import qualified Data.Map as Map hiding (Map)
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Cont
import Data.Dynamic
type Fun m = (m Dynamic -> m Dynamic)
data LambdaTerm term
= Lam !String term
| App term term
| Var !String
type IState m = (Int,Map Int (m Dynamic),Int) -- record instead of tuple would be more robust
type Ref = Int
prjF :: (Typeable (m Dynamic), MonadError String m) => m Dynamic -> m (Fun m)
prjF = prj'
phiLambda :: (MonadError String m,
MonadState (IState m) m,
Typeable (m Dynamic),
Pause m (Either Dynamic b),
Typeable b,
MonadReader (Map String (m Dynamic)) m) =>
LambdaTerm (m Dynamic) -> m Dynamic
phiLambda (Var v) = do step; lookupEnv v
{-
phiLambda (Lam v b) = do env <- ask
return $ inj (\v' -> do loc <- newRef undefined
let thunk =
do r <- v'
writeRef loc
(return r)
return r
writeRef loc thunk
let env' = addToFM env v (readRef loc)
inEnv env' b)
-}
phiLambda (Lam v b) = do env <- ask
return $ inj (\v' -> do rr <- thunkify v'
inEnv (Map.insert v rr env) b)
phiLambda (App f x) = do f' <- prjF f; env <- ask; f' (inEnv env x)
thunkify :: (MonadState (IState m) m) => m Dynamic -> m (m Dynamic)
thunkify c = do
loc <- newRef (error "empty reference")
let thunk = do r <- c
writeRef loc (return r)
return r
writeRef loc thunk
return (readRef loc)
lookupEnv :: (MonadReader (Map String (m Dynamic)) m,
Typeable (m Dynamic),
MonadError String m) => String -> m Dynamic
lookupEnv k = do env <- ask
let v = Map.lookup k env
maybe (throwError ("unbound variable: "++k)) id v
inEnv :: (MonadReader (Map String (m Dynamic)) m) =>
Map String (m Dynamic) -> m Dynamic -> m Dynamic
inEnv env b = local (const env) b
step :: (MonadState (IState m) m, MonadError String m,
Typeable b,
Pause m (Either Dynamic b)) => m ()
step = do (c,hp,fuel) <- get
if fuel == 0 then do refuel <- pause $ Left . inj
put (c,hp,refuel)
else put (c,hp,fuel-1)
newRef :: (MonadState (IState m) m) => m Dynamic -> m Ref
newRef v = do (c,hp,fuel) <- get
put (c+1,Map.insert c v hp,fuel)
return c
readRef :: (MonadState (IState m) m) => Ref -> m Dynamic
readRef loc = do (_,hp,_) <- get; let {Just x = Map.lookup loc hp}; x
writeRef :: (MonadState (IState m) m) => Ref -> m Dynamic -> m ()
writeRef loc v = do (c,hp,fuel) <- get
put (c,Map.insert loc v hp,fuel)
instance Functor LambdaTerm where
fmap _ (Var v) = Var v
fmap f (Lam v b) = Lam v (f b)
fmap f (App g x) = App (f g) (f x)