import BidirTT.Value namespace BidirTT abbrev EvalM := Except String mutual partial def eval : Env → Tm → EvalM Val | env, .var i => match env[i]? with | some v => pure v | none => throw s!"bad de Bruijn index {i} in environment of size {env.length}" | env, .lam t => pure (.lam (.mk env t)) | env, .app t u => do let vt ← eval env t let vu ← eval env u vApp vt vu | env, .pi a b => do let va ← eval env a pure (.pi va (.mk env b)) | env, .sig a b => do let va ← eval env a pure (.sig va (.mk env b)) | env, .pair t u => do let vt ← eval env t let vu ← eval env u pure (.pair vt vu) | env, .fst t => do let vt ← eval env t vFst vt | env, .snd t => do let vt ← eval env t vSnd vt | _, .univ i => pure (.univ i) | env, .letE _ t u => do let vt ← eval env t eval (vt :: env) u partial def vApp : Val → Val → EvalM Val | .lam c, u => cApp c u | t, u => pure (.app t u) partial def vFst : Val → EvalM Val | .pair a _ => pure a | t => pure (.fst t) partial def vSnd : Val → EvalM Val | .pair _ b => pure b | t => pure (.snd t) partial def cApp : Closure → Val → EvalM Val | .mk env body, v => eval (v :: env) body end partial def quote : Lvl → Val → EvalM Tm | l, .var x => if x < l then pure (.var (l - x - 1)) else throw s!"bad level {x} while quoting at level {l}" | l, .app t u => do let qt ← quote l t let qu ← quote l u pure (.app qt qu) | l, .fst t => do let qt ← quote l t pure (.fst qt) | l, .snd t => do let qt ← quote l t pure (.snd qt) | l, .lam c => do let body ← cApp c (.var l) let qb ← quote (l + 1) body pure (.lam qb) | l, .pi a c => do let qa ← quote l a let body ← cApp c (.var l) let qb ← quote (l + 1) body pure (.pi qa qb) | l, .sig a c => do let qa ← quote l a let body ← cApp c (.var l) let qb ← quote (l + 1) body pure (.sig qa qb) | l, .pair a b => do let qa ← quote l a let qb ← quote l b pure (.pair qa qb) | _, .univ i => pure (.univ i) private def andThen (lhs : EvalM Bool) (rhs : Unit → EvalM Bool) : EvalM Bool := do if (← lhs) then rhs () else pure false partial def conv : Lvl → Val → Val → EvalM Bool | _, .univ i, .univ j => pure (i == j) | l, .pi a c, .pi a' c' => andThen (conv l a a') fun _ => do let b ← cApp c (.var l) let b' ← cApp c' (.var l) conv (l + 1) b b' | l, .sig a c, .sig a' c' => andThen (conv l a a') fun _ => do let b ← cApp c (.var l) let b' ← cApp c' (.var l) conv (l + 1) b b' | l, .lam c, .lam c' => do let body ← cApp c (.var l) let body' ← cApp c' (.var l) conv (l + 1) body body' | l, .lam c, t => do let body ← cApp c (.var l) let apped ← vApp t (.var l) conv (l + 1) body apped | l, t, .lam c => do let apped ← vApp t (.var l) let body ← cApp c (.var l) conv (l + 1) apped body | l, .pair a b, .pair a' b' => andThen (conv l a a') fun _ => conv l b b' | l, .pair a b, p => andThen (do let fstp ← vFst p conv l a fstp) fun _ => do let sndp ← vSnd p conv l b sndp | l, p, .pair a b => andThen (do let fstp ← vFst p conv l fstp a) fun _ => do let sndp ← vSnd p conv l sndp b | _, .var x, .var y => pure (x == y) | l, .app t u, .app t' u' => andThen (conv l t t') fun _ => conv l u u' | l, .fst t, .fst t' => conv l t t' | l, .snd t, .snd t' => conv l t t' | _, _, _ => pure false end BidirTT