|
| 1 | +{-# LANGUAGE NamedFieldPuns #-} |
| 2 | +module PiSig where |
| 3 | + |
| 4 | +-- loosely based on http://www.andres-loeh.de/LambdaPi/ |
| 5 | + |
| 6 | +import Control.Monad.Error |
| 7 | + |
| 8 | +infixl 3 :@: |
| 9 | + |
| 10 | +type BName = Int |
| 11 | +data FName = Global String | Local BName | Quote BName |
| 12 | + deriving (Show, Eq) |
| 13 | + |
| 14 | +-- start simply typed |
| 15 | +data Ty = TyFree FName | TyArrow Ty Ty |
| 16 | + deriving (Show, Eq) |
| 17 | +data TermInfer = Ann TermCheck Ty | Bound BName | Free FName | TermInfer :@: TermCheck |
| 18 | + deriving (Show, Eq) |
| 19 | +data TermCheck = Infer TermInfer | Lam TermCheck |
| 20 | + deriving (Show, Eq) |
| 21 | +data Neutral = NFree FName | NApp Neutral Value |
| 22 | + deriving (Show, Eq) |
| 23 | +data Value = VNeut Neutral | VClo Closure |
| 24 | + deriving (Show, Eq) |
| 25 | + |
| 26 | +data Code = CClo [Code] | CLit Value | CRef BName | CApp |
| 27 | + deriving (Show, Eq) |
| 28 | +type Env = [Value] |
| 29 | +type Closure = (Env, [Code]) |
| 30 | + |
| 31 | +data State = State {s_code :: [Code], s_env, s_stack :: Env, s_cont :: Maybe State} |
| 32 | +s_init codes = State {s_code = codes, s_env = [], s_stack = [], s_cont = Nothing} |
| 33 | +s_push st val = st{s_stack = val : s_stack st} |
| 34 | +s_pop st@State {s_stack = val : vals} = (val, st{s_stack = vals}) |
| 35 | +s_lookup State {s_env} bname = s_env !! bname |
| 36 | +s_isFinal State {s_code = [], s_cont = Nothing} = True |
| 37 | +s_isFinal _ = False |
| 38 | +s_ret st |
| 39 | + | not (s_isFinal st) && null (s_code st) = s_cont st |
| 40 | + | otherwise = Just st |
| 41 | +s_next st@State {s_code = code : codes} = (code, st{s_code = codes}) |
| 42 | +-- TODO: assert empty code implies empty stack? |
| 43 | +s_step State {s_code = [], s_stack = [val], s_cont = Just st'} = s_push st' val |
| 44 | +s_step st@State {s_code = code : codes} = exec code st{s_code = codes} |
| 45 | + |
| 46 | +vfree n = VNeut (NFree n) |
| 47 | +vapp st (VNeut neutral) arg = s_push st $ VNeut (NApp neutral arg) |
| 48 | +vapp st (VClo (env, codes)) arg = State codes (arg : env) [] $ s_ret st |
| 49 | + |
| 50 | +exec (CClo codes) st@State {s_env} = s_push st $ VClo (s_env, codes) |
| 51 | +exec (CLit val) st = s_push st val |
| 52 | +exec (CRef bname) st = s_push st $ s_lookup st bname |
| 53 | +exec CApp st = vapp st'' proc arg |
| 54 | + where |
| 55 | + (proc, st') = s_pop st |
| 56 | + (arg, st'') = s_pop st' |
| 57 | + |
| 58 | +eval = dropWhile (not . s_isFinal) . iterate s_step |
| 59 | + |
| 60 | +data Kind = Star |
| 61 | + deriving (Show) |
| 62 | +data Info = HasKind Kind | HasType Ty |
| 63 | + deriving (Show) |
| 64 | +type Context = [(FName, Info)] |
| 65 | +cxt_lookup cxt name = case lookup name cxt of |
| 66 | + Just info -> return info |
| 67 | + Nothing -> throwError "unknown identifier" |
| 68 | + |
| 69 | +kind cxt (TyFree name) Star = do |
| 70 | + HasKind Star <- cxt_lookup cxt name |
| 71 | + return () |
| 72 | +kind cxt (TyArrow tyProc tyArg) Star = kind cxt tyProc Star >> kind cxt tyArg Star |
| 73 | + |
| 74 | +typeInfer level cxt (Ann term ty) = |
| 75 | + kind cxt ty Star >> typeCheck level cxt term ty >> return ty |
| 76 | +typeInfer level cxt (Free name) = do |
| 77 | + HasType ty <- cxt_lookup cxt name |
| 78 | + return ty |
| 79 | +typeInfer level cxt (proc :@: arg) = do |
| 80 | + tyProc <- typeInfer level cxt proc |
| 81 | + case tyProc of |
| 82 | + TyArrow tyArg tyRes -> typeCheck level cxt arg tyArg >> return tyRes |
| 83 | + _ -> throwError $ "applying non-proc type: " ++ show tyProc |
| 84 | +typeCheck level cxt (Infer term) ty = do |
| 85 | + ty' <- typeInfer level cxt term |
| 86 | + unless (ty == ty') $ throwError $ "expected type '" ++ show ty ++ "' but inferred: " ++ show ty' |
| 87 | +typeCheck level cxt (Lam term) (TyArrow tyArg tyRes) = typeCheck (level + 1) |
| 88 | + ((Local level, HasType tyArg) : cxt) (substCheck 0 (Free (Local level)) term) tyRes |
| 89 | +typeCheck _ _ _ _ = throwError "type error" |
| 90 | + |
| 91 | +substInfer = undefined -- level |
| 92 | +substCheck = undefined |
| 93 | + |
| 94 | +quote level (VClo (env, codes)) = undefined |
| 95 | +quote level (VNeut neutral) = Infer (neutQuote level neutral) |
| 96 | +neutQuote level (NFree name) = boundFree level name |
| 97 | +neutQuote level (NApp neut arg) = neutQuote level neut :@: quote level arg |
| 98 | + |
| 99 | +boundFree level (Quote depth) = Bound (level - depth - 1) |
| 100 | +boundFree level name = Free name |
0 commit comments