yi-0.6.0: Yi/Interpreter.hs
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
{- A mockup haskell interpreter -}
module Yi.Interpreter (
UExpr(..),
parse, rename, interpret, toMono) where
import Yi.Prelude
import Data.Dynamic
import Control.Monad.Error ()
import Data.Maybe
import Control.Applicative
import qualified Data.Map as M
import Data.Traversable
import Prelude (words)
import Data.Foldable
import GHC.Base (Any)
import Unsafe.Coerce
type Var = String
-- Big hurdle: supporting constraints.
-- unsafeCoerce show ~~> ambiguous type variable. Thus we need a
data Type = Poly Var [Constraint] Type
| TyApp Type Type
| TyCon TyCon
| TyVar Var
fromMono tr = mkTyConApp' tc (fmap fromMono args)
where (tc,args) = splitTyConApp tr
funTyCon = fst $ splitTyConApp $ typeOf (id :: Char -> Char)
mkTyConApp' tyCon = foldl TyApp (TyCon tyCon)
mkFunTy t1 t2 = mkTyConApp funTyCon [t1,t2]
-- funResultTy' t1 t2 = case unify t1 (mkFunTy t2 (TyVar "frt")) of
funResultTy' = error "funResultTy'"
data Constraint = Constraint TypeClass [Type]
data TypeClass = Action
-- | Polymorphic dynamic type
data PolyDyn = PolyDyn Type Any
subst :: Var ->Type ->Type -> Type
subst v s t0 = case t0 of
(Poly v' cs t) -> if v == v' then t0 else Poly v' (fmap substConstraint cs) (subst v s t)
(TyApp t1 t2) -> TyApp (subst v s t1) (subst v s t2)
(TyVar v') -> if v == v' then s else t0
_ -> t0
where substConstraint (Constraint tc ts) = Constraint tc (fmap (subst v s) ts)
data Atom = AVar String
| AString String
| AChar Char
| AInt Int
instance Show Atom where
show (AInt i) = show i
show (AVar s) = s
show (AString s) = show s
show (AChar s) = show s
type Env = M.Map String [Dynamic]
type Env' = M.Map String PolyDyn
parse :: (Monad m) => String -> m (UExpr Atom)
parse s = return $ foldl1 UApp $ fmap (UVal . AVar) $ words $ s -- trivial parser that builds a single application of vars
-- If we want a nicer parser we should use haskell-src package.
data UExpr a where
UVal :: a -> UExpr a
UApp :: UExpr a -> UExpr a -> UExpr a
instance Functor UExpr where
fmap = fmapDefault
instance Foldable UExpr where
foldMap = foldMapDefault
instance Traversable UExpr where
traverse f (UVal a) = UVal <$> f a
traverse f (UApp l r) = UApp <$> traverse f l <*> traverse f r
instance Show a => Show (UExpr a) where
showsPrec _ (UVal a) = shows a
showsPrec p (UApp f a) = showParen (p > 0)
(showsPrec 0 f . showChar ' ' . showsPrec 1 a)
type Err = String
rename :: Env -> UExpr Atom -> Either Err (UExpr [Dynamic])
rename env = mapM renameOne
where
renameOne (AVar v) = do
case M.lookup v env of
Just x -> Right x
Nothing -> Left $ v ++ " not found in the environment"
renameOne (AChar x) = box x
renameOne (AString x) = box x
renameOne (AInt x) = box x
box x = return [toDyn x]
rename' :: Env' -> UExpr Atom -> Either Err (UExpr PolyDyn)
rename' env = mapM renameOne
where
renameOne (AVar v) = do
case M.lookup v env of
Just x -> Right x
Nothing -> Left $ v ++ " not found in the environment"
renameOne (AChar x) = box x
renameOne (AString x) = box x
renameOne (AInt x) = box x
box :: Typeable a => a -> Either err PolyDyn
box = Right . polyBox
polyBox :: Typeable a => a -> PolyDyn
polyBox x = PolyDyn (fromMono $ typeOf x) (unsafeCoerce x)
interpret :: UExpr [Dynamic] -> Either Err [Dynamic]
interpret (UVal da) = return $ da
interpret (UApp df da) = do
t1 <- interpret df
t2 <- interpret da
return $ catMaybes [dynApply f a | f <- t1, a <- t2]
dynApply' (PolyDyn t1 f) (PolyDyn t2 x) =
case funResultTy' t1 t2 of
Just t3 ->Just (PolyDyn t3 ((unsafeCoerce f) x))
Nothing ->Nothing
interpret' (UVal da) = return $ da
interpret' (UApp df da) = do
f <- interpret' df
a <- interpret' da
dynApply' f a
toMono :: forall a. Typeable a => [Dynamic] -> Either Err a
toMono rs = case catMaybes $ fmap fromDynamic rs of
[] -> Left $ "value doesn't have type " ++ show (typeOf (undefined::a))
[r] -> Right r
_ -> error "eval': ambiguous types"
-- eval :: Env -> String -> Either Err [Dynamic]
-- eval env s = interpret =<< rename env =<< parse s
-- test :: String -> Maybe String
-- test s = case eval symTable s of
-- Right [result] -> fromDynamic result
-- Right [] -> Just "type error"
-- Right _ -> Just "ambiguous"
-- Left err -> Just err
-- where
-- symTable = M.fromList [("one", [toDyn (1::Int)]),
-- ("show",[toDyn (show :: Int -> String)]) ]