|
| 1 | +{-# LANGUAGE NoMonomorphismRestriction, TupleSections #-} |
| 2 | +module DirectCalc where |
| 3 | + |
| 4 | +import qualified Data.Map as M |
| 5 | +import Data.Maybe |
| 6 | +import Control.Monad.State |
| 7 | +import Control.Monad.Error |
| 8 | + |
| 9 | +type Ident = String |
| 10 | +type Arity = Int |
| 11 | +type EnvKey = Arity |
| 12 | +type Env = [Value] |
| 13 | +data Name = Free Ident | Bound EnvKey |
| 14 | + deriving (Show, Eq, Ord) |
| 15 | + |
| 16 | +data Term = |
| 17 | + Type | Arrow Term Term | Ann Term Term | |
| 18 | + Var Name | App Term Term | Lam Term |
| 19 | + deriving (Show, Eq) |
| 20 | + |
| 21 | +data Neutral = NVar Ident | NApp Neutral Value |
| 22 | + deriving (Show, Eq) |
| 23 | + |
| 24 | +type Closure = (Env, Term) |
| 25 | +data Value = VNeut Neutral | VClo Closure | VType | VArrow Value Value |
| 26 | + deriving (Show, Eq) |
| 27 | + |
| 28 | +vvar (Free ident) env = VNeut $ NVar ident |
| 29 | +vvar (Bound key) env = env !! key |
| 30 | +vapp (VNeut neutral) arg = VNeut $ NApp neutral arg |
| 31 | +vapp (VClo (cenv, cbody)) arg = bigstep cbody $ arg : cenv |
| 32 | + |
| 33 | +bigstep (Var name) env = vvar name env |
| 34 | +bigstep (App tproc targ) env = vapp proc arg |
| 35 | + where proc = bigstep tproc env |
| 36 | + arg = bigstep targ env |
| 37 | +bigstep (Lam body) env = VClo (env, body) |
| 38 | + |
| 39 | +data TContext = TContext{tc_tvars :: M.Map EnvKey Term, |
| 40 | + tc_bvars :: M.Map Name [Term], |
| 41 | + tc_nextFresh :: EnvKey} |
| 42 | +tc_fresh = do |
| 43 | + cxt <- get |
| 44 | + let fresh = tc_nextFresh cxt |
| 45 | + put $ cxt{tc_nextFresh = fresh + 1} |
| 46 | + return $ Var $ Bound fresh |
| 47 | +tc_bvarFresh name = do |
| 48 | + fresh <- tc_fresh |
| 49 | + cxt <- get |
| 50 | + let tys = fresh : (maybe [] id $ M.lookup name $ tc_bvars cxt) |
| 51 | + put $ cxt{tc_bvars = M.insert name tys $ tc_bvars cxt} |
| 52 | + return fresh |
| 53 | +tc_find key = do |
| 54 | + cxt <- get |
| 55 | + let (term, tvars) = _find (tc_tvars cxt) key [] |
| 56 | + put $ cxt{tc_tvars = tvars} |
| 57 | + return term |
| 58 | + where |
| 59 | + _find tvars key accKeys = case M.lookup key tvars of |
| 60 | + Just (Var (Bound next)) -> _find tvars next $ key : accKeys |
| 61 | + Just term -> (term, merge term) |
| 62 | + Nothing -> (vkey, merge vkey) |
| 63 | + where vkey = Var $ Bound key |
| 64 | + merge term = M.union tvars $ M.fromList $ map (, term) accKeys |
| 65 | +tc_assign key term = do |
| 66 | + cxt <- get |
| 67 | + put $ cxt{tc_tvars = M.insert key term $ tc_tvars cxt} |
| 68 | + |
| 69 | +subterms (Arrow ta tb) = [ta, tb] |
| 70 | +subterms (App ta tb) = [ta, tb] |
| 71 | +subterms (Ann ta tb) = [ta, tb] |
| 72 | +subterms (Lam body) = [body] |
| 73 | +subterms _ = [] |
| 74 | + |
| 75 | +occurs name (Var vname) = name == vname |
| 76 | +occurs name term = any (occurs name) $ subterms term |
| 77 | + |
| 78 | +sunify (Ann ta tb) other = liftM (Ann ta) $ sunify tb other |
| 79 | +sunify other ann@(Ann ta' tb') = sunify ann other |
| 80 | +sunify (Var (Free _)) _ = error "something went wrong" |
| 81 | +sunify tvar@(Var (Bound key)) other = do |
| 82 | + term <- tc_find key |
| 83 | + if tvar == term |
| 84 | + then if occurs (Bound key) term |
| 85 | + then throwError $ "occurs check failed: " ++ show (key, term) |
| 86 | + else tc_assign key term >> return term |
| 87 | + else sunify term other |
| 88 | +sunify other (Var name) = sunify (Var name) other |
| 89 | +sunify Type Type = return Type |
| 90 | +sunify (Arrow ta tb) (Arrow ta' tb') = |
| 91 | + liftM2 Arrow (sunify ta ta') $ sunify tb tb' |
| 92 | +-- TODO: reduce apps and inside lambdas for non-simple unify |
| 93 | +sunify (App ta tb) (App ta' tb') = liftM2 App (sunify ta ta') $ sunify tb tb' |
| 94 | +sunify (Lam body) (Lam body') = liftM Lam $ sunify body body' |
| 95 | +sunify ta tb = throwError $ "type mismatch: " ++ show (ta, tb) |
| 96 | + |
| 97 | +--sunifyE lenv renv = undefined |
| 98 | + |
| 99 | +sbvar name = do |
| 100 | + cxt <- get |
| 101 | + let bvars = tc_bvars cxt |
| 102 | + case M.lookup name bvars of |
| 103 | + Nothing -> tc_bvarFresh name |
| 104 | + Just (ty : tys) -> do |
| 105 | + final <- foldM sunify ty tys |
| 106 | + put $ cxt{tc_bvars = M.insert name [final] bvars} |
| 107 | + return final |
| 108 | + |
| 109 | +bigtype Type = return Type |
| 110 | +bigtype (Arrow ta tb) = bigtype ta >> bigtype tb >> return Type |
| 111 | +bigtype (Ann term ty) = |
| 112 | + bigtype ty >>= sunify Type >> bigtype term >>= sunify ty >> return ty |
| 113 | +bigtype (Var name) = tc_bvarFresh name |
| 114 | +bigtype (Lam body) = do -- TODO: how to quantify? free var dependencies? |
| 115 | + tbody <- bigtype body |
| 116 | + targ <- sbvar $ Bound 0 |
| 117 | + return $ Arrow targ tbody |
| 118 | + |
| 119 | +{-bigtype (App proc arg) = (tyRes, env')-} |
| 120 | + {-where (tyProc, penv) = bigtype proc-} |
| 121 | + {-(tyArg, aenv) = bigtype arg-} |
| 122 | + {-tyRes = undefined -- create fresh var-} |
| 123 | + {-tenv = sunify tyProc $ Arrow tyArg tyRes-} |
| 124 | + {-env = sunifyE penv aenv-} |
| 125 | + {-env' = sunifyE env tenv-} |
| 126 | + |
| 127 | +-- data TermD_ lterm rterm = |
0 commit comments