Port Eval.newt

This commit is contained in:
2025-01-03 22:49:07 -08:00
parent b87999a64d
commit 46434cc555
4 changed files with 1124 additions and 56 deletions

337
done/Lib/Eval.newt Normal file
View File

@@ -0,0 +1,337 @@
module Lib.Eval
import Lib.Types
import Lib.TopContext
import Data.IORef
import Data.Fin
import Data.List
import Data.SnocList
import Data.Vect
import Data.SortedMap
eval : Env -> Mode -> Tm -> M Val
-- REVIEW everything is evalutated whether it's needed or not
-- It would be nice if the environment were lazy.
-- e.g. case is getting evaluated when passed to a function because
-- of dependencies in pi-types, even if the dependency isn't used
infixl 8 _$$_
_$$_ : Closure -> Val -> M Val
_$$_ (MkClosure env tm) u = eval (u :: env) CBN tm
vapp : Val -> Val -> M Val
vapp (VLam _ _ _ _ t) u = t $$ u
vapp (VVar fc k sp) u = pure $ VVar fc k (sp :< u)
vapp (VRef fc nm def sp) u = pure $ VRef fc nm def (sp :< u)
vapp (VMeta fc k sp) u = pure $ VMeta fc k (sp :< u)
vapp t u = error' "impossible in vapp \{show t} to \{show u}\n"
vappSpine : Val -> SnocList Val -> M Val
vappSpine t Lin = pure t
vappSpine t (xs :< x) = do
rest <- vappSpine t xs
vapp rest x
lookupVar : Env -> Int -> Maybe Val
lookupVar env k = let l = cast $ length env in
if k > l
then Nothing
else case getAt (cast $ lvl2ix l k) env of
Just v@(VVar fc k' sp) => if k == k' then Nothing else Just v
Just v => Just v
Nothing => Nothing
-- hoping to apply what we got via pattern matching
unlet : Env -> Val -> M Val
unlet env t@(VVar fc k sp) = case lookupVar env k of
Just tt@(VVar fc' k' sp') => do
debug $ \ _ => "lookup \{show k} is \{show tt}"
if k' == k then pure t else (vappSpine (VVar fc' k' sp') sp >>= unlet env)
Just t => vappSpine t sp >>= unlet env
Nothing => do
debug $ \ _ => "lookup \{show k} is Nothing in env \{show env}"
pure t
unlet env x = pure x
tryEval : Env -> Val -> M (Maybe Val)
tryEval env (VRef fc k _ sp) = do
top <- get
case lookup k top of
Just (MkEntry _ name ty (Fn tm)) =>
catchError (
do
debug $ \ _ => "app \{show name} to \{show sp}"
vtm <- eval Nil CBN tm
debug $ \ _ => "tm is \{render 90 $ pprint Nil tm}"
val <- vappSpine vtm sp
case val of
VCase _ _ _ => pure Nothing
v => pure $ Just v)
(\ _ => pure Nothing)
_ => pure Nothing
tryEval _ _ = pure Nothing
-- Force far enough to compare types
forceType : Env -> Val -> M Val
forceType env (VMeta fc ix sp) = do
meta <- lookupMeta ix
case meta of
(Unsolved x k xs _ _ _) => pure (VMeta fc ix sp)
(Solved _ k t) => vappSpine t sp >>= forceType env
forceType env x = do
Just x' <- tryEval env x
| _ => pure x
forceType env x'
evalCase : Env -> Mode -> Val -> List CaseAlt -> M (Maybe Val)
evalCase env mode sc@(VRef _ nm _ sp) (cc@(CaseCons name nms t) :: xs) = do
top <- get
if nm == name
then do
debug $ \ _ => "ECase \{show nm} \{show sp} \{show nms} \{showTm t}"
go env (sp <>> Nil) nms
else case lookup nm top of
(Just (MkEntry _ str type (DCon k str1))) => evalCase env mode sc xs
-- bail for a stuck function
_ => pure Nothing
where
go : Env -> List Val -> List String -> M (Maybe Val)
go env (arg :: args) (nm :: nms) = go (arg :: env) args nms
go env args Nil = do
t' <- eval env mode t
Just <$> vappSpine t' (Lin <>< args)
go env Nil rest = pure Nothing
-- REVIEW - this is handled in the caller already
evalCase env mode sc@(VVar fc k sp) alts = case lookupVar env k of
Just tt@(VVar fc' k' sp') => do
debug $ \ _ => "lookup \{show k} is \{show tt}"
if k' == k
then pure Nothing
else do
val <- vappSpine (VVar fc' k' sp') sp
evalCase env mode val alts
Just t => do
val <- vappSpine t sp
evalCase env mode val alts
Nothing => do
debug $ \ _ => "lookup \{show k} is Nothing in env \{show env}"
pure Nothing
evalCase env mode sc (CaseDefault u :: xs) = Just <$> eval (sc :: env) mode u
evalCase env mode sc cc = do
debug $ \ _ => "CASE BAIL sc \{show sc} vs " -- \{show cc}"
debug $ \ _ => "env is \{show env}"
pure Nothing
-- So smalltt says:
-- Smalltt has the following approach:
-- - Top-level and local definitions are lazy.
-- - We instantiate Pi types during elaboration with lazy values.
-- - Applications headed by top-level variables are lazy.
-- - Any other function application is call-by-value during evaluation.
-- TODO maybe add glueing
eval env mode (Ref fc x def) = pure $ VRef fc x def Lin
eval env mode (App _ t u) = do
t' <- eval env mode t
u' <- eval env mode u
vapp t' u'
eval env mode (UU fc) = pure (VU fc)
eval env mode (Erased fc) = pure (VErased fc)
eval env mode (Meta fc i) = do
meta <- lookupMeta i
case meta of
(Unsolved _ k xs _ _ _) => pure $ VMeta fc i Lin
(Solved _ k t) => pure $ t
eval env mode (Lam fc x icit rig t) = pure $ VLam fc x icit rig (MkClosure env t)
eval env mode (Pi fc x icit rig a b) = do
a' <- eval env mode a
pure $ VPi fc x icit rig a' (MkClosure env b)
eval env mode (Let fc nm t u) = do
t' <- eval env mode t
u' <- eval (VVar fc (cast $ length env) Lin :: env) mode u
pure $ VLet fc nm t' u'
eval env mode (LetRec fc nm ty t u) = do
ty' <- eval env mode ty
t' <- eval (VVar fc (length' env) Lin :: env) mode t
u' <- eval (VVar fc (length' env) Lin :: env) mode u
pure $ VLetRec fc nm ty' t' u'
-- Here, we assume env has everything. We push levels onto it during type checking.
-- I think we could pass in an l and assume everything outside env is free and
-- translate to a level
eval env mode (Bnd fc i) = case getAt' i env of
Just rval => pure rval
Nothing => error fc "Bad deBruin index \{show i}"
eval env mode (Lit fc lit) = pure $ VLit fc lit
eval env mode tm@(Case fc sc alts) = do
-- TODO we need to be able to tell eval to expand aggressively here.
sc' <- eval env mode sc
sc' <- unlet env sc' -- try to expand lets from pattern matching
sc' <- forceType env sc'
vsc <- eval env mode sc
vcase <- evalCase env mode sc' alts
pure $ fromMaybe (VCase fc vsc alts) vcase
quote : (lvl : Int) -> Val -> M Tm
quoteSp : (lvl : Int) -> Tm -> SnocList Val -> M Tm
quoteSp lvl t Lin = pure t
quoteSp lvl t (xs :< x) = do
t' <- quoteSp lvl t xs
x' <- quote lvl x
pure $ App emptyFC t' x'
quote l (VVar fc k sp) = if k < l
then quoteSp l (Bnd fc (lvl2ix l k )) sp -- level to index
else error fc "Bad index in quote \{show k} depth \{show l}"
quote l (VMeta fc i sp) = do
meta <- lookupMeta i
case meta of
(Unsolved _ k xs _ _ _) => quoteSp l (Meta fc i) sp
(Solved _ k t) => vappSpine t sp >>= quote l
quote l (VLam fc x icit rig t) = do
val <- t $$ VVar emptyFC l Lin
tm <- quote (1 + l) val
pure $ Lam fc x icit rig tm
quote l (VPi fc x icit rig a b) = do
a' <- quote l a
val <- b $$ VVar emptyFC l Lin
tm <- quote (1 + l) val
pure $ Pi fc x icit rig a' tm
quote l (VLet fc nm t u) = do
t' <- quote l t
u' <- quote (1 + l) u
pure $ Let fc nm t' u'
quote l (VLetRec fc nm ty t u) = do
ty' <- quote l ty
t' <- quote (1 + l) t
u' <- quote (1 + l) u
pure $ LetRec fc nm ty' t' u'
quote l (VU fc) = pure (UU fc)
quote l (VRef fc n def sp) = quoteSp l (Ref fc n def) sp
quote l (VCase fc sc alts) = do
sc' <- quote l sc
pure $ Case fc sc' alts
quote l (VLit fc lit) = pure $ Lit fc lit
quote l (VErased fc) = pure $ Erased fc
-- Can we assume closed terms?
-- ezoo only seems to use it at Nil, but essentially does this:
nf : Env -> Tm -> M Tm
nf env t = eval env CBN t >>= quote (length' env)
nfv : Env -> Tm -> M Tm
nfv env t = eval env CBV t >>= quote (length' env)
prvalCtx : {{ctx : Context}} -> Val -> M String
prvalCtx {{ctx}} v = do
tm <- quote ctx.lvl v
pure $ interpolate $ pprint (map fst ctx.types) tm
-- REVIEW - might be easier if we inserted the meta without a bunch of explicit App
-- I believe Kovacs is doing that.
-- we need to walk the whole thing
-- meta in Tm have a bunch of args, which should be the relevant
-- parts of the scope. So, meta has a bunch of lambdas, we've got a bunch of
-- args and we need to beta reduce, which seems like a lot of work for nothing
-- Could we put the "good bits" of the Meta in there and write it to Bnd directly
-- off of scope? I guess this might get dicey when a meta is another meta applied
-- to something.
-- ok, so we're doing something that looks lot like eval, having to collect args,
-- pull the def, and apply spine. Eval is trying for WHNF, so it doesn't walk the
-- whole thing. (We'd like to insert metas inside lambdas.)
zonk : TopContext -> Int -> Env -> Tm -> M Tm
zonkBind : TopContext -> Int -> Env -> Tm -> M Tm
zonkBind top l env tm = zonk top (1 + l) (VVar (getFC tm) l Lin :: env) tm
-- I don't know if app needs an FC...
appSpine : Tm -> List Tm -> Tm
appSpine t Nil = t
appSpine t (x :: xs) = appSpine (App (getFC t) t x) xs
-- REVIEW When metas are subst in, the fc point elsewhere
-- We might want to update when it is solved and update recursively?
-- For errors, I think we want to pretend the code has been typed in place
tweakFC : FC -> Tm -> Tm
tweakFC fc (Bnd fc1 k) = Bnd fc k
tweakFC fc (Ref fc1 nm x) = Ref fc nm x
tweakFC fc (UU fc1) = UU fc
tweakFC fc (Meta fc1 k) = Meta fc k
tweakFC fc (Lam fc1 nm icit rig t) = Lam fc nm icit rig t
tweakFC fc (App fc1 t u) = App fc t u
tweakFC fc (Pi fc1 nm icit x t u) = Pi fc nm icit x t u
tweakFC fc (Case fc1 t xs) = Case fc t xs
tweakFC fc (Let fc1 nm t u) = Let fc nm t u
tweakFC fc (LetRec fc1 nm ty t u) = LetRec fc nm ty t u
tweakFC fc (Lit fc1 lit) = Lit fc lit
tweakFC fc (Erased fc1) = Erased fc
-- TODO replace this with a variant on nf
zonkApp : TopContext -> Int -> Env -> Tm -> List Tm -> M Tm
zonkApp top l env (App fc t u) sp = do
u' <- zonk top l env u
zonkApp top l env t (u' :: sp)
zonkApp top l env t@(Meta fc k) sp = do
meta <- lookupMeta k
case meta of
(Solved _ j v) => do
sp' <- traverse (eval env CBN) sp
debug $ \ _ => "zonk \{show k} -> \{show v} spine \{show sp'}"
foo <- vappSpine v (Lin <>< sp')
debug $ \ _ => "-> result is \{show foo}"
tweakFC fc <$> quote l foo
(Unsolved x j xs _ _ _) => pure $ appSpine t sp
zonkApp top l env t sp = do
t' <- zonk top l env t
pure $ appSpine t' sp
zonkAlt : TopContext -> Int -> Env -> CaseAlt -> M CaseAlt
zonkAlt top l env (CaseDefault t) = CaseDefault <$> zonkBind top l env t
zonkAlt top l env (CaseLit lit t) = CaseLit lit <$> zonkBind top l env t
zonkAlt top l env (CaseCons name args t) = CaseCons name args <$> go l env args t
where
go : Int -> Env -> List String -> Tm -> M Tm
go l env Nil tm = zonk top l env t
go l env (x :: xs) tm = go (1 + l) (VVar (getFC tm) l Lin :: env) xs tm
zonk top l env t = case t of
(Meta fc k) => zonkApp top l env t Nil
(Lam fc nm icit rig u) => Lam fc nm icit rig <$> (zonk top (1 + l) (VVar fc l Lin :: env) u)
(App fc t u) => do
u' <- zonk top l env u
zonkApp top l env t (u' :: Nil)
(Pi fc nm icit rig a b) => Pi fc nm icit rig <$> zonk top l env a <*> zonkBind top l env b
(Let fc nm t u) => Let fc nm <$> zonk top l env t <*> zonkBind top l env u
(LetRec fc nm ty t u) => LetRec fc nm <$> zonk top l env ty <*> zonkBind top l env t <*> zonkBind top l env u
(Case fc sc alts) => Case fc <$> zonk top l env sc <*> traverse (zonkAlt top l env) alts
UU fc => pure $ UU fc
Lit fc lit => pure $ Lit fc lit
Bnd fc ix => pure $ Bnd fc ix
Ref fc ix def => pure $ Ref fc ix def
Erased fc => pure $ Erased fc

667
done/Lib/Parser.newt Normal file
View File

@@ -0,0 +1,667 @@
module Lib.Parser
-- NOW Still working on this.
import Data.Maybe
import Data.String
import Lib.Parser.Impl
import Lib.Syntax
import Lib.Token
import Lib.Types
lazy : a. (Unit Parser a) Parser a
lazy pa = pa MkUnit
ident : Parser String
ident = token Ident <|> token MixFix
uident : Parser String
uident = token UIdent
parenWrap : a. Parser a -> Parser a
parenWrap pa = do
symbol "("
t <- pa
symbol ")"
pure t
braces : a. Parser a -> Parser a
braces pa = do
symbol "{"
t <- pa
symbol "}"
pure t
dbraces : a. Parser a -> Parser a
dbraces pa = do
symbol "{{"
t <- pa
symbol "}}"
pure t
optional : a. Parser a -> Parser (Maybe a)
optional pa = Just <$> pa <|> pure Nothing
stringLit : Parser Raw
stringLit = do
fc <- getPos
t <- token StringKind
pure $ RLit fc (LString t)
-- typeExpr is term with arrows.
typeExpr : Parser Raw
term : (Parser Raw)
interp : Parser Raw
interp = do
token StartInterp
tm <- term
token EndInterp
pure tm
interpString : Parser Raw
interpString = do
-- fc <- getPos
ignore $ token StartQuote
part <- term
parts <- many (stringLit <|> interp)
ignore $ token EndQuote
pure $ foldl append part parts
where
append : Raw -> Raw -> Raw
append t u =
let fc = getFC t in
(RApp (getFC t) (RApp fc (RVar fc "_++_") t Explicit) u Explicit)
intLit : Parser Raw
intLit = do
fc <- getPos
t <- token Number
pure $ RLit fc (LInt (stringToInt t))
charLit : Parser Raw
charLit = do
fc <- getPos
v <- token Character
pure $ RLit fc (LChar $ strIndex v 0)
lit : Parser Raw
lit = intLit <|> interpString <|> stringLit <|> charLit
-- helpful when we've got some / many and need FC for each
addPos : a. Parser a -> Parser (FC × a)
addPos pa = _,_ <$> getPos <*> pa
asAtom : Parser Raw
asAtom = do
fc <- getPos
nm <- ident
asPat <- optional $ keyword "@" *> parenWrap typeExpr
case asPat of
Just exp => pure $ RAs fc nm exp
Nothing => pure $ RVar fc nm
-- the inside of Raw
atom : Parser Raw
atom = do
pure MkUnit
RU <$> getPos <* keyword "U"
-- <|> RVar <$> getPos <*> ident
<|> asAtom
<|> RVar <$> getPos <*> uident
<|> RVar <$> getPos <*> token Projection
<|> lit
<|> RImplicit <$> getPos <* keyword "_"
<|> RHole <$> getPos <* keyword "?"
<|> parenWrap typeExpr
-- Argument to a Spine
pArg : Parser (Icit × FC × Raw)
pArg = do
fc <- getPos
(\x => Explicit, fc, x) <$> atom
<|> (\x => Implicit, fc, x) <$> braces typeExpr
<|> (\x => Auto, fc, x) <$> dbraces typeExpr
AppSpine : U
AppSpine = List (Icit × FC × Raw)
pratt : Operators -> Int -> String -> Raw -> AppSpine -> Parser (Raw × AppSpine)
pratt ops prec stop left spine = do
(left, spine) <- runPrefix stop left spine
let (left, spine) = projectHead left spine
let spine = runProject spine
case spine of
Nil => pure (left, Nil)
((Explicit, fc, tm@(RVar x nm)) :: rest) =>
if nm == stop then pure (left,spine) else
case lookupMap' nm ops of
Just (MkOp name p fix False rule) => if p < prec
then pure (left, spine)
else
runRule p fix stop rule (RApp fc (RVar fc name) left Explicit) rest
Just _ => fail "expected operator"
Nothing =>
if isPrefixOf "." nm
then pratt ops prec stop (RApp (getFC tm) tm left Explicit) rest
else pratt ops prec stop (RApp (getFC left) left tm Explicit) rest
((icit, fc, tm) :: rest) => pratt ops prec stop (RApp (getFC left) left tm icit) rest
where
projectHead : Raw -> AppSpine -> (Raw × AppSpine)
projectHead t sp@((Explicit, fc', RVar fc nm) :: rest) =
if isPrefixOf "." nm
then projectHead (RApp fc (RVar fc nm) t Explicit) rest
else (t,sp)
projectHead t sp = (t, sp)
-- we need to check left/AppSpine first
-- we have a case above for when the next token is a projection, but
-- we need this to make projection bind tighter than app
runProject : AppSpine -> AppSpine
runProject (t@(Explicit, fc', tm) :: u@(Explicit, _, RVar fc nm) :: rest) =
if isPrefixOf "." nm
then runProject ((Explicit, fc', RApp fc (RVar fc nm) tm Explicit) :: rest)
else (t :: u :: rest)
runProject tms = tms
-- left has our partially applied operator and we're picking up args
-- for the rest of the `_`
runRule : Int -> Fixity -> String -> List String -> Raw -> AppSpine -> Parser (Raw × AppSpine)
runRule p fix stop Nil left spine = pure (left, spine)
runRule p fix stop ("" :: Nil) left spine = do
let pr = case fix of
InfixR => p
_ => p + 1
case spine of
((_, fc, right) :: rest) => do
(right, rest) <- pratt ops pr stop right rest
pratt ops prec stop (RApp (getFC left) left right Explicit) rest
_ => fail "trailing operator"
runRule p fix stop (nm :: rule) left spine = do
case spine of
Nil => fail "short"
((_, _, right) :: rest) => do
(right,rest) <- pratt ops 0 nm right rest -- stop!!
let ((_,fc',RVar fc name) :: rest) = rest
| _ => fail "expected \{nm}"
if name == nm
then runRule p fix stop rule (RApp (getFC left) left right Explicit) rest
else fail "expected \{nm}"
-- run any prefix operators
runPrefix : String -> Raw -> AppSpine -> Parser (Raw × AppSpine)
runPrefix stop (RVar fc nm) spine =
case lookupMap' nm ops of
-- TODO False should be an error here
Just (MkOp name p fix True rule) => do
runRule p fix stop rule (RVar fc name) spine
_ =>
pure (left, spine)
runPrefix stop left spine = pure (left, spine)
parseOp : Parser Raw
parseOp = do
fc <- getPos
ops <- getOps
hd <- atom
rest <- many pArg
(res, Nil) <- pratt ops 0 "" hd rest
| _ => fail "extra stuff"
pure res
-- TODO case let? We see to only have it for `do`
-- try (keyword "let" >> symbol "(")
letExpr : Parser Raw
letExpr = do
keyword "let"
alts <- startBlock $ someSame $ letAssign
keyword' "in"
scope <- typeExpr
pure $ foldl mkLet scope (reverse alts)
where
mkLet : Raw String × FC × Maybe Raw × Raw Raw
mkLet acc (n,fc,ty,v) = RLet fc n (fromMaybe (RImplicit fc) ty) v acc
letAssign : Parser (Name × FC × Maybe Raw × Raw)
letAssign = do
fc <- getPos
name <- ident
-- TODO type assertion
ty <- optional (keyword ":" *> typeExpr)
keyword "="
t <- typeExpr
pure (name,fc,ty,t)
pLamArg : Parser (Icit × String × Maybe Raw)
pLamArg = impArg <|> autoArg <|> expArg
<|> (\ x => (Explicit, x, Nothing)) <$> (ident <|> uident)
<|> keyword "_" *> pure (Explicit, "_", Nothing)
where
impArg : Parser (Icit × String × Maybe Raw)
impArg = do
nm <- braces (ident <|> uident)
ty <- optional (symbol ":" >> typeExpr)
pure (Implicit, nm, ty)
autoArg : Parser (Icit × String × Maybe Raw)
autoArg = do
nm <- dbraces (ident <|> uident)
ty <- optional (symbol ":" >> typeExpr)
pure (Auto, nm, ty)
expArg : Parser (Icit × String × Maybe Raw)
expArg = do
nm <- parenWrap (ident <|> uident)
ty <- optional (symbol ":" >> typeExpr)
pure (Explicit, nm, ty)
lamExpr : Parser Raw
lamExpr = do
pos <- getPos
keyword "\\" <|> keyword "λ"
args <- some $ addPos pLamArg
keyword "=>"
scope <- typeExpr
pure $ foldr mkLam scope args
where
mkLam : FC × Icit × Name × Maybe Raw Raw Raw
mkLam (fc, icit, name, ty) sc = RLam fc (BI fc name icit Many) sc
caseAlt : Parser RCaseAlt
caseAlt = do
pure MkUnit
pat <- typeExpr
keyword "=>"
t <- term
pure $ MkAlt pat t
caseExpr : Parser Raw
caseExpr = do
fc <- getPos
keyword "case"
sc <- term
keyword "of"
alts <- startBlock $ someSame $ caseAlt
pure $ RCase fc sc alts
caseLamExpr : Parser Raw
caseLamExpr = do
fc <- getPos
try ((keyword "\\" <|> keyword "λ") *> keyword "case")
alts <- startBlock $ someSame $ caseAlt
pure $ RLam fc (BI fc "$case" Explicit Many) $ RCase fc (RVar fc "$case") alts
doExpr : Parser Raw
doStmt : Parser DoStmt
caseLet : Parser Raw
caseLet = do
-- look ahead so we can fall back to normal let
fc <- getPos
try (keyword "let" >> symbol "(")
pat <- typeExpr
symbol ")"
keyword "="
sc <- typeExpr
alts <- startBlock $ manySame $ symbol "|" *> caseAlt
keyword "in"
body <- term
pure $ RCase fc sc (MkAlt pat body :: alts)
doCaseLet : Parser DoStmt
doCaseLet = do
-- look ahead so we can fall back to normal let
-- Maybe make it work like arrow?
fc <- getPos
try (keyword "let" >> symbol "(")
pat <- typeExpr
symbol ")"
keyword "="
sc <- typeExpr
alts <- startBlock $ manySame $ symbol "|" *> caseAlt
bodyFC <- getPos
body <- RDo <$> getPos <*> someSame doStmt
pure $ DoExpr fc (RCase fc sc (MkAlt pat body :: alts))
doArrow : Parser DoStmt
doArrow = do
fc <- getPos
left <- typeExpr
(Just _) <- optional $ keyword "<-"
| _ => pure $ DoExpr fc left
right <- term
alts <- startBlock $ manySame $ symbol "|" *> caseAlt
pure $ DoArrow fc left right alts
doLet : Parser DoStmt
doLet = do
fc <- getPos
keyword "let"
nm <- ident
keyword "="
tm <- term
pure $ DoLet fc nm tm
doStmt
= doCaseLet
<|> doLet
<|> doArrow
doExpr = RDo <$> getPos <* keyword "do" <*> (startBlock $ someSame doStmt)
parseIfThen : Parser Raw
parseIfThen = do
fc <- getPos
keyword "if"
a <- term
keyword "then"
b <- term
keyword "else"
c <- term
pure $ RIf fc a b c
term' : Parser Raw
term' = caseExpr
<|> caseLet
<|> letExpr
<|> caseLamExpr
<|> lamExpr
<|> doExpr
<|> parseIfThen
-- Make this last for better error messages
<|> parseOp
term = do
t <- term'
rest <- many (_,_ <$> getPos <* keyword "$" <*> term')
pure $ apply t rest
where
apply : Raw -> List (FC × Raw) -> Raw
apply t Nil = t
apply t ((fc,x) :: xs) = RApp fc t (apply x xs) Explicit
varname : Parser String
varname = (ident <|> uident <|> keyword "_" *> pure "_")
quantity : Parser Quant
quantity = fromMaybe Many <$> optional (Zero <$ keyword "0")
ebind : Parser Telescope
ebind = do
-- don't commit until we see the ":"
symbol "("
quant <- quantity
names <- try (some (addPos varname) <* symbol ":")
ty <- typeExpr
symbol ")"
pure $ map (makeBind quant ty) names
where
makeBind : Quant Raw FC × String (BindInfo × Raw)
makeBind quant ty (pos, name) = (BI pos name Explicit quant, ty)
ibind : Parser Telescope
ibind = do
-- I've gone back and forth on this, but I think {m a b} is more useful than {Int}
symbol "{"
quant <- quantity
names <- (some (addPos varname))
ty <- optional (symbol ":" *> typeExpr)
symbol "}"
pure $ map (makeBind quant ty) names
where
makeBind : Quant Maybe Raw FC × String BindInfo × Raw
makeBind quant ty (pos, name) = (BI pos name Implicit quant, fromMaybe (RImplicit pos) ty)
abind : Parser Telescope
abind = do
-- for this, however, it would be nice to allow {{Monad A}}
symbol "{{"
name <- optional $ try (addPos varname <* symbol ":")
ty <- typeExpr
symbol "}}"
case name of
Just (pos,name) => pure ((BI pos name Auto Many, ty) :: Nil)
Nothing => pure ((BI (getFC ty) "_" Auto Many, ty) :: Nil)
arrow : Parser Unit
arrow = symbol "->" <|> symbol ""
-- Collect a bunch of binders (A : U) {y : A} -> ...
forAll : Parser Raw
forAll = do
keyword "forall" <|> keyword ""
all <- some (addPos varname)
keyword "."
scope <- typeExpr
pure $ foldr mkPi scope all
where
mkPi : FC × String Raw Raw
mkPi (fc, n) sc = RPi fc (BI fc n Implicit Zero) (RImplicit fc) sc
binders : Parser Raw
binders = do
binds <- many (abind <|> ibind <|> ebind)
arrow
scope <- typeExpr
pure $ foldr mkBind scope (join binds)
where
mkBind : (BindInfo × Raw) -> Raw -> Raw
mkBind (info, ty) scope = RPi (getFC info) info ty scope
typeExpr
= binders
<|> forAll
<|> (do
fc <- getPos
exp <- term
scope <- optional (arrow *> typeExpr)
case scope of
Nothing => pure exp
-- consider Maybe String to represent missing
(Just scope) => pure $ RPi fc (BI fc "_" Explicit Many) exp scope)
-- And top level stuff
parseSig : Parser Decl
parseSig = TypeSig <$> getPos <*> try (some (ident <|> uident <|> token Projection) <* keyword ":") <*> typeExpr
parseImport : Parser Import
parseImport = do
fc <- getPos
keyword "import"
ident <- uident
rest <- many $ token Projection
let name = joinBy "" (ident :: rest)
pure $ MkImport fc name
-- Do we do pattern stuff now? or just name = lambda?
-- TODO multiple names
parseMixfix : Parser Decl
parseMixfix = do
fc <- getPos
fix <- InfixL <$ keyword "infixl"
<|> InfixR <$ keyword "infixr"
<|> Infix <$ keyword "infix"
prec <- token Number
ops <- some $ token MixFix
for ops $ \ op => addOp op (cast prec) fix
pure $ PMixFix fc ops (cast prec) fix
getName : Raw -> Parser String
getName (RVar x nm) = pure nm
getName (RApp x t u icit) = getName t
getName tm = fail "bad LHS"
parseDef : Parser Decl
parseDef = do
fc <- getPos
t <- typeExpr
nm <- getName t
keyword "="
body <- typeExpr
wfc <- getPos
w <- optional $ do
keyword "where"
startBlock $ manySame $ (parseSig <|> parseDef)
let body = maybe body (\ decls => RWhere wfc decls body) w
-- these get collected later
pure $ Def fc nm ((t, body) :: Nil) -- (MkClause fc Nil t body :: Nil)
parsePType : Parser Decl
parsePType = do
fc <- getPos
keyword "ptype"
id <- uident
ty <- optional $ do
keyword ":"
typeExpr
pure $ PType fc id ty
parsePFunc : Parser Decl
parsePFunc = do
fc <- getPos
keyword "pfunc"
nm <- ident
used <- optional (keyword "uses" >> parenWrap (many $ uident <|> ident <|> token MixFix))
keyword ":"
ty <- typeExpr
keyword ":="
src <- token JSLit
pure $ PFunc fc nm (fromMaybe Nil used) ty src
parseShortData : Parser Decl
parseShortData = do
fc <- getPos
keyword "data"
lhs <- typeExpr
keyword "="
sigs <- sepBy (keyword "|") typeExpr
pure $ ShortData fc lhs sigs
parseData : Parser Decl
parseData = do
fc <- getPos
-- commit when we hit ":"
name <- try $ (keyword "data" *> (uident <|> ident <|> token MixFix) <* keyword ":")
ty <- typeExpr
keyword "where"
decls <- startBlock $ manySame $ parseSig
pure $ Data fc name ty decls
nakedBind : Parser Telescope
nakedBind = do
names <- some (addPos varname)
pure $ map makeBind names
where
makeBind : FC × String (BindInfo × Raw)
makeBind (pos, name) = (BI pos name Explicit Many, RImplicit pos)
parseRecord : Parser Decl
parseRecord = do
fc <- getPos
keyword "record"
name <- uident
teles <- many $ ebind <|> nakedBind
keyword "where"
cname <- optional $ keyword "constructor" *> (uident <|> token MixFix)
decls <- startBlock $ manySame $ parseSig
pure $ Record fc name (join teles) cname decls
parseClass : Parser Decl
parseClass = do
fc <- getPos
keyword "class"
name <- uident
teles <- many $ ebind <|> nakedBind
keyword "where"
decls <- startBlock $ manySame $ parseSig
pure $ Class fc name (join teles) decls
parseInstance : Parser Decl
parseInstance = do
fc <- getPos
keyword "instance"
ty <- typeExpr
-- is it a forward declaration
(Just _) <- optional $ keyword "where"
| _ => pure $ Instance fc ty Nothing
decls <- startBlock $ manySame $ parseDef
pure $ Instance fc ty (Just decls)
-- Not sure what I want here.
-- I can't get a Tm without a type, and then we're covered by the other stuff
parseNorm : Parser Decl
parseNorm = DCheck <$> getPos <* keyword "#check" <*> typeExpr <* keyword ":" <*> typeExpr
parseDecl : Parser Decl
parseDecl = parseMixfix <|> parsePType <|> parsePFunc
<|> parseNorm <|> parseData <|> parseShortData <|> parseSig <|> parseDef
<|> parseClass <|> parseInstance <|> parseRecord
parseModHeader : Parser (FC × String)
parseModHeader = do
sameLevel (keyword "module")
fc <- getPos
name <- uident
rest <- many $ token Projection
-- FIXME use QName
let name = joinBy "" (name :: rest)
pure (fc, name)
parseImports : Parser (List Import)
parseImports = manySame parseImport
parseMod : Parser Module
parseMod = do
sameLevel (keyword "module")
name <- uident
rest <- many $ token Projection
imports <- manySame parseImport
decls <- manySame parseDecl
let name = joinBy "" (name :: rest)
pure $ MkModule name imports decls
data ReplCmd =
Def Decl
| Norm Raw -- or just name?
| Check Raw
-- Eventually I'd like immediate actions in the file, like lean, but I
-- also want to REPL to work and we can do that first.
parseRepl : Parser ReplCmd
parseRepl = Def <$> parseDecl <|> Norm <$ keyword "#nf" <*> typeExpr
<|> Check <$ keyword "#check" <*> typeExpr

View File

@@ -534,6 +534,7 @@ getAt _ Nil = Nothing
getAt Z (x :: xs) = Just x getAt Z (x :: xs) = Just x
getAt (S k) (x :: xs) = getAt k xs getAt (S k) (x :: xs) = getAt k xs
splitOn : a. {{Eq a}} a List a List (List a) splitOn : a. {{Eq a}} a List a List (List a)
splitOn {a} v xs = go Nil xs splitOn {a} v xs = go Nil xs
where where
@@ -849,3 +850,14 @@ instance ∀ a. {{Show a}} → Show (Maybe a) where
pfunc isPrefixOf uses (True False): String String Bool := `(pfx, s) => s.startsWith(pfx) ? True : False` pfunc isPrefixOf uses (True False): String String Bool := `(pfx, s) => s.startsWith(pfx) ? True : False`
pfunc strIndex : String Int Char := `(s, ix) => s[ix]` pfunc strIndex : String Int Char := `(s, ix) => s[ix]`
instance a. {{Show a}} Show (SnocList a) where
show xs = show (xs <>> Nil)
getAt' : a. Int List a Maybe a
getAt' i xs = getAt (cast i) xs
length' : a. List a Int
length' Nil = 0
length' (x :: xs) = 1 + length' xs

View File

@@ -37,7 +37,9 @@ vapp t u = error' "impossible in vapp \{show t} to \{show u}\n"
export export
vappSpine : Val -> SnocList Val -> M Val vappSpine : Val -> SnocList Val -> M Val
vappSpine t [<] = pure t vappSpine t [<] = pure t
vappSpine t (xs :< x) = vapp !(vappSpine t xs) x vappSpine t (xs :< x) = do
rest <- vappSpine t xs
vapp rest x
@@ -65,16 +67,18 @@ unlet env x = pure x
export export
tryEval : Env -> Val -> M (Maybe Val) tryEval : Env -> Val -> M (Maybe Val)
tryEval env (VRef fc k _ sp) = tryEval env (VRef fc k _ sp) = do
case lookup k !(get) of top <- get
case lookup k top of
Just (MkEntry _ name ty (Fn tm)) => Just (MkEntry _ name ty (Fn tm)) =>
catchError ( catchError (
do do
debug "app \{name} to \{show sp}" debug "app \{show name} to \{show sp}"
vtm <- eval [] CBN tm vtm <- eval [] CBN tm
debug "tm is \{pprint [] tm}" debug "tm is \{render 90 $ pprint [] tm}"
case !(vappSpine vtm sp) of val <- vappSpine vtm sp
VCase{} => pure Nothing case val of
VCase _ _ _ => pure Nothing
v => pure $ Just v) v => pure $ Just v)
(\ _ => pure Nothing) (\ _ => pure Nothing)
_ => pure Nothing _ => pure Nothing
@@ -84,7 +88,9 @@ tryEval _ _ = pure Nothing
-- Force far enough to compare types -- Force far enough to compare types
export export
forceType : Env -> Val -> M Val forceType : Env -> Val -> M Val
forceType env (VMeta fc ix sp) = case !(lookupMeta ix) of forceType env (VMeta fc ix sp) = do
meta <- lookupMeta ix
case meta of
(Unsolved x k xs _ _ _) => pure (VMeta fc ix sp) (Unsolved x k xs _ _ _) => pure (VMeta fc ix sp)
(Solved _ k t) => vappSpine t sp >>= forceType env (Solved _ k t) => vappSpine t sp >>= forceType env
forceType env x = do forceType env x = do
@@ -93,40 +99,44 @@ forceType env x = do
forceType env x' forceType env x'
evalCase : Env -> Mode -> Val -> List CaseAlt -> M (Maybe Val) evalCase : Env -> Mode -> Val -> List CaseAlt -> M (Maybe Val)
evalCase env mode sc@(VRef _ nm _ sp) (cc@(CaseCons name nms t) :: xs) = evalCase env mode sc@(VRef _ nm _ sp) (cc@(CaseCons name nms t) :: xs) = do
top <- get
if nm == name if nm == name
then do then do
debug "ECase \{nm} \{show sp} \{show nms} \{showTm t}" debug "ECase \{show nm} \{show sp} \{show nms} \{showTm t}"
go env (sp <>> []) nms go env (sp <>> []) nms
else case lookup nm !(get) of else case lookup nm top of
(Just (MkEntry _ str type (DCon k str1))) => evalCase env mode sc xs (Just (MkEntry _ str type (DCon k str1))) => evalCase env mode sc xs
-- bail for a stuck function -- bail for a stuck function
_ => pure Nothing _ => pure Nothing
where where
go : Env -> List Val -> List String -> M (Maybe Val) go : Env -> List Val -> List String -> M (Maybe Val)
go env (arg :: args) (nm :: nms) = go (arg :: env) args nms go env (arg :: args) (nm :: nms) = go (arg :: env) args nms
go env args [] = Just <$> vappSpine !(eval env mode t) ([<] <>< args) go env args [] = do
t' <- eval env mode t
Just <$> vappSpine t' ([<] <>< args)
go env [] rest = pure Nothing go env [] rest = pure Nothing
-- REVIEW - this is handled in the caller already -- REVIEW - this is handled in the caller already
evalCase env mode sc@(VVar fc k sp) alts = case lookupVar env k of evalCase env mode sc@(VVar fc k sp) alts = case lookupVar env k of
Just tt@(VVar fc' k' sp') => do Just tt@(VVar fc' k' sp') => do
debug "lookup \{show k} is \{show tt}" debug "lookup \{show k} is \{show tt}"
if k' == k then pure Nothing if k' == k
else evalCase env mode !(vappSpine (VVar fc' k' sp') sp) alts then pure Nothing
Just t => evalCase env mode !(vappSpine t sp) alts else do
val <- vappSpine (VVar fc' k' sp') sp
evalCase env mode val alts
Just t => do
val <- vappSpine t sp
evalCase env mode val alts
Nothing => do Nothing => do
debug "lookup \{show k} is Nothing in env \{show env}" debug "lookup \{show k} is Nothing in env \{show env}"
pure Nothing pure Nothing
evalCase env mode sc (CaseDefault u :: xs) = pure $ Just !(eval (sc :: env) mode u) evalCase env mode sc (CaseDefault u :: xs) = Just <$> eval (sc :: env) mode u
evalCase env mode sc cc = do evalCase env mode sc cc = do
debug "CASE BAIL sc \{show sc} vs \{show cc}" debug "CASE BAIL sc \{show sc} vs \{show cc}"
debug "env is \{show env}" debug "env is \{show env}"
pure Nothing pure Nothing
bind : Val -> Env -> Env
bind v env = v :: env
-- So smalltt says: -- So smalltt says:
-- Smalltt has the following approach: -- Smalltt has the following approach:
-- - Top-level and local definitions are lazy. -- - Top-level and local definitions are lazy.
@@ -137,17 +147,30 @@ bind v env = v :: env
-- TODO maybe add glueing -- TODO maybe add glueing
eval env mode (Ref fc x def) = pure $ VRef fc x def [<] eval env mode (Ref fc x def) = pure $ VRef fc x def [<]
eval env mode (App _ t u) = vapp !(eval env mode t) !(eval env mode u) eval env mode (App _ t u) = do
t' <- eval env mode t
u' <- eval env mode u
vapp t' u'
eval env mode (UU fc) = pure (VU fc) eval env mode (UU fc) = pure (VU fc)
eval env mode (Erased fc) = pure (VErased fc) eval env mode (Erased fc) = pure (VErased fc)
eval env mode (Meta fc i) = eval env mode (Meta fc i) = do
case !(lookupMeta i) of meta <- lookupMeta i
case meta of
(Unsolved _ k xs _ _ _) => pure $ VMeta fc i [<] (Unsolved _ k xs _ _ _) => pure $ VMeta fc i [<]
(Solved _ k t) => pure $ t (Solved _ k t) => pure $ t
eval env mode (Lam fc x icit rig t) = pure $ VLam fc x icit rig (MkClosure env t) eval env mode (Lam fc x icit rig t) = pure $ VLam fc x icit rig (MkClosure env t)
eval env mode (Pi fc x icit rig a b) = pure $ VPi fc x icit rig !(eval env mode a) (MkClosure env b) eval env mode (Pi fc x icit rig a b) = do
eval env mode (Let fc nm t u) = pure $ VLet fc nm !(eval env mode t) !(eval (VVar fc (length env) [<] :: env) mode u) a' <- eval env mode a
eval env mode (LetRec fc nm ty t u) = pure $ VLetRec fc nm !(eval env mode ty) !(eval (VVar fc (length env) [<] :: env) mode t) !(eval (VVar fc (length env) [<] :: env) mode u) pure $ VPi fc x icit rig a' (MkClosure env b)
eval env mode (Let fc nm t u) = do
t' <- eval env mode t
u' <- eval (VVar fc (length env) [<] :: env) mode u
pure $ VLet fc nm t' u'
eval env mode (LetRec fc nm ty t u) = do
ty' <- eval env mode ty
t' <- eval (VVar fc (length env) [<] :: env) mode t
u' <- eval (VVar fc (length env) [<] :: env) mode u
pure $ VLetRec fc nm ty' t' u'
-- Here, we assume env has everything. We push levels onto it during type checking. -- Here, we assume env has everything. We push levels onto it during type checking.
-- I think we could pass in an l and assume everything outside env is free and -- I think we could pass in an l and assume everything outside env is free and
-- translate to a level -- translate to a level
@@ -161,8 +184,9 @@ eval env mode tm@(Case fc sc alts) = do
sc' <- eval env mode sc sc' <- eval env mode sc
sc' <- unlet env sc' -- try to expand lets from pattern matching sc' <- unlet env sc' -- try to expand lets from pattern matching
sc' <- forceType env sc' sc' <- forceType env sc'
pure $ fromMaybe (VCase fc !(eval env mode sc) alts) vsc <- eval env mode sc
!(evalCase env mode sc' alts) vcase <- evalCase env mode sc' alts
pure $ fromMaybe (VCase fc vsc alts) vcase
export export
quote : (lvl : Nat) -> Val -> M Tm quote : (lvl : Nat) -> Val -> M Tm
@@ -170,23 +194,42 @@ quote : (lvl : Nat) -> Val -> M Tm
quoteSp : (lvl : Nat) -> Tm -> SnocList Val -> M Tm quoteSp : (lvl : Nat) -> Tm -> SnocList Val -> M Tm
quoteSp lvl t [<] = pure t quoteSp lvl t [<] = pure t
quoteSp lvl t (xs :< x) = quoteSp lvl t (xs :< x) = do
pure $ App emptyFC !(quoteSp lvl t xs) !(quote lvl x) t' <- quoteSp lvl t xs
x' <- quote lvl x
pure $ App emptyFC t' x'
quote l (VVar fc k sp) = if k < l quote l (VVar fc k sp) = if k < l
then quoteSp l (Bnd fc (lvl2ix l k )) sp -- level to index then quoteSp l (Bnd fc (lvl2ix l k )) sp -- level to index
else ?borken else error fc "Bad index in quote \{show k} depth \{show l}"
quote l (VMeta fc i sp) = quote l (VMeta fc i sp) = do
case !(lookupMeta i) of meta <- lookupMeta i
case meta of
(Unsolved _ k xs _ _ _) => quoteSp l (Meta fc i) sp (Unsolved _ k xs _ _ _) => quoteSp l (Meta fc i) sp
(Solved _ k t) => quote l !(vappSpine t sp) (Solved _ k t) => vappSpine t sp >>= quote l
quote l (VLam fc x icit rig t) = pure $ Lam fc x icit rig !(quote (S l) !(t $$ VVar emptyFC l [<])) quote l (VLam fc x icit rig t) = do
quote l (VPi fc x icit rig a b) = pure $ Pi fc x icit rig !(quote l a) !(quote (S l) !(b $$ VVar emptyFC l [<])) val <- t $$ VVar emptyFC l [<]
quote l (VLet fc nm t u) = pure $ Let fc nm !(quote l t) !(quote (S l) u) tm <- quote (S l) val
quote l (VLetRec fc nm ty t u) = pure $ LetRec fc nm !(quote l ty) !(quote (S l) t) !(quote (S l) u) pure $ Lam fc x icit rig tm
quote l (VPi fc x icit rig a b) = do
a' <- quote l a
val <- b $$ VVar emptyFC l [<]
tm <- quote (S l) val
pure $ Pi fc x icit rig a' tm
quote l (VLet fc nm t u) = do
t' <- quote l t
u' <- quote (S l) u
pure $ Let fc nm t' u'
quote l (VLetRec fc nm ty t u) = do
ty' <- quote l ty
t' <- quote (S l) t
u' <- quote (S l) u
pure $ LetRec fc nm ty' t' u'
quote l (VU fc) = pure (UU fc) quote l (VU fc) = pure (UU fc)
quote l (VRef fc n def sp) = quoteSp l (Ref fc n def) sp quote l (VRef fc n def sp) = quoteSp l (Ref fc n def) sp
quote l (VCase fc sc alts) = pure $ Case fc !(quote l sc) alts quote l (VCase fc sc alts) = do
sc' <- quote l sc
pure $ Case fc sc' alts
quote l (VLit fc lit) = pure $ Lit fc lit quote l (VLit fc lit) = pure $ Lit fc lit
quote l (VErased fc) = pure $ Erased fc quote l (VErased fc) = pure $ Erased fc
@@ -194,15 +237,17 @@ quote l (VErased fc) = pure $ Erased fc
-- ezoo only seems to use it at [], but essentially does this: -- ezoo only seems to use it at [], but essentially does this:
export export
nf : Env -> Tm -> M Tm nf : Env -> Tm -> M Tm
nf env t = quote (length env) !(eval env CBN t) nf env t = eval env CBN t >>= quote (length env)
export export
nfv : Env -> Tm -> M Tm nfv : Env -> Tm -> M Tm
nfv env t = quote (length env) !(eval env CBV t) nfv env t = eval env CBV t >>= quote (length env)
export export
prvalCtx : {auto ctx : Context} -> Val -> M String prvalCtx : {auto ctx : Context} -> Val -> M String
prvalCtx v = pure $ interpolate $ pprint (toList $ map fst ctx.types) !(quote ctx.lvl v) prvalCtx v = do
tm <- quote ctx.lvl v
pure $ interpolate $ pprint (toList $ map fst ctx.types) tm
-- REVIEW - might be easier if we inserted the meta without a bunch of explicit App -- REVIEW - might be easier if we inserted the meta without a bunch of explicit App
-- I believe Kovacs is doing that. -- I believe Kovacs is doing that.
@@ -249,17 +294,22 @@ tweakFC fc (Erased fc1) = Erased fc
-- TODO replace this with a variant on nf -- TODO replace this with a variant on nf
zonkApp : TopContext -> Nat -> Env -> Tm -> List Tm -> M Tm zonkApp : TopContext -> Nat -> Env -> Tm -> List Tm -> M Tm
zonkApp top l env (App fc t u) sp = zonkApp top l env t (!(zonk top l env u) :: sp) zonkApp top l env (App fc t u) sp = do
zonkApp top l env t@(Meta fc k) sp = case !(lookupMeta k) of u' <- zonk top l env u
zonkApp top l env t (u' :: sp)
zonkApp top l env t@(Meta fc k) sp = do
meta <- lookupMeta k
case meta of
(Solved _ j v) => do (Solved _ j v) => do
sp' <- traverse (eval env CBN) sp sp' <- traverse (eval env CBN) sp
debug "zonk \{show k} -> \{show v} spine \{show sp'}" debug "zonk \{show k} -> \{show v} spine \{show sp'}"
foo <- vappSpine v ([<] <>< sp') foo <- vappSpine v ([<] <>< sp')
debug "-> result is \{show foo}" debug "-> result is \{show foo}"
tweakFC fc <$> quote l foo tweakFC fc <$> quote l foo
(Unsolved x j xs _ _ _) => pure $ appSpine t sp (Unsolved x j xs _ _ _) => pure $ appSpine t sp
zonkApp top l env t sp = pure $ appSpine !(zonk top l env t) sp zonkApp top l env t sp = do
t' <- zonk top l env t
pure $ appSpine t' sp
zonkAlt : TopContext -> Nat -> Env -> CaseAlt -> M CaseAlt zonkAlt : TopContext -> Nat -> Env -> CaseAlt -> M CaseAlt
zonkAlt top l env (CaseDefault t) = CaseDefault <$> zonkBind top l env t zonkAlt top l env (CaseDefault t) = CaseDefault <$> zonkBind top l env t
@@ -273,7 +323,9 @@ zonkAlt top l env (CaseCons name args t) = CaseCons name args <$> go l env args
zonk top l env t = case t of zonk top l env t = case t of
(Meta fc k) => zonkApp top l env t [] (Meta fc k) => zonkApp top l env t []
(Lam fc nm icit rig u) => Lam fc nm icit rig <$> (zonk top (S l) (VVar fc l [<] :: env) u) (Lam fc nm icit rig u) => Lam fc nm icit rig <$> (zonk top (S l) (VVar fc l [<] :: env) u)
(App fc t u) => zonkApp top l env t [!(zonk top l env u)] (App fc t u) => do
u' <- zonk top l env u
zonkApp top l env t [u']
(Pi fc nm icit rig a b) => Pi fc nm icit rig <$> zonk top l env a <*> zonkBind top l env b (Pi fc nm icit rig a b) => Pi fc nm icit rig <$> zonk top l env a <*> zonkBind top l env b
(Let fc nm t u) => Let fc nm <$> zonk top l env t <*> zonkBind top l env u (Let fc nm t u) => Let fc nm <$> zonk top l env t <*> zonkBind top l env u
(LetRec fc nm ty t u) => LetRec fc nm <$> zonk top l env ty <*> zonkBind top l env t <*> zonkBind top l env u (LetRec fc nm ty t u) => LetRec fc nm <$> zonk top l env ty <*> zonkBind top l env t <*> zonkBind top l env u