{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE BlockArguments #-} {-# LANGUAGE OverloadedStrings #-} module Evaluate where import qualified Control.Exception as Exc import Control.Monad.Except import Control.Monad.Reader import Control.Concurrent import qualified Data.IntMap.Strict as IntMap import qualified Data.Sequence as Seq import qualified Data.Text as T import Elaboration.Monad import GHC.Stack (HasCallStack) import Generics.SYB (mkT, everywhere) import Syntax import System.IO.Unsafe import Value import Data.Foldable import Syntax.Pretty (showWithPrec) evaluate :: HasCallStack => Env -> Term -> Value evaluate env (Var (Bound i)) = case Seq.lookup i (locals env) of Just x -> x Nothing -> error $ "Variable of index " ++ show i ++ " not in scope" evaluate _ (Con t) = VGlued (HCon t) mempty Nothing evaluate _ Type = VType evaluate env (Pi p t d r) = VPi p t (evaluate env d) (Closure env r) evaluate env (Lam p t b) = VLam p t (Closure env b) evaluate env (App p f x) = vApp (evaluate env f) p (evaluate env x) evaluate env (Sigma t d r) = VSigma t (evaluate env d) (Closure env r) evaluate env (Pair a b) = VPair (evaluate env a) (evaluate env b) evaluate env (Proj1 a) = vProj1 (evaluate env a) evaluate env (Proj2 a) = vProj2 (evaluate env a) evaluate _ (Meta m) = VGlued (HMeta m) mempty Nothing evaluate env (NewMeta m mask) = VGlued (HMeta m) (getVals (locals env) mask) Nothing where getVals Seq.Empty [] = Seq.Empty getVals (v Seq.:<| seq) (BDBound _:bds) = AppEx v Seq.:<| getVals seq bds getVals (_ Seq.:<| seq) (BDDefined _:bds) = getVals seq bds evaluate _ Top = VTop evaluate _ Unit = VUnit evaluate _ Refl = VGlued HRefl mempty Nothing evaluate _ Coe = function Im (T.pack "A") $ \a -> function Im (T.pack "B") $ \b -> function Ex (T.pack "p") $ \p -> function Ex (T.pack "x") $ \x -> vCoe a b p x evaluate _ Cong = function Im (T.pack "A") $ \a -> function Im (T.pack "B") $ \b -> function Im (T.pack "x") $ \x -> function Im (T.pack "y") $ \y -> function Ex (T.pack "f") $ \f -> function Ex (T.pack "p") $ \p -> vCong a b x y f p evaluate _ Sym = function Im (T.pack "A") $ \a -> function Im (T.pack "x") $ \x -> function Im (T.pack "y") $ \y -> function Ex (T.pack "p") $ \p -> vSym a x y p evaluate e (Let _ _ c d) = evaluate e' d where e' = e { locals = evaluate e c Seq.:<| locals e } evaluate env (Id a b c) = vId (evaluate env a) (evaluate env b) (evaluate env c) vId :: Value -> Value -> Value -> Value vId kind a b = let stuck = VEq kind a b solve = VEqG kind a b never = solve vBottom always = solve VTop in case force kind of VType -> case (a, b) of (VTop, VTop) -> always (VType, VType) -> always (VEqG _ _ _ a, b) -> vId VType a b (a, VEqG _ _ _ b) -> vId VType a b (VEq a _ _, VEq b _ _) -> vId VType a b (VPi i _ d r, VPi i' _ d' r') | i == i' -> solve $ exists "p" (vId VType d d') $ \p -> forAll Ex "x" d $ \x -> vId VType (r $$ x) (r' $$ vCoe d d' p x) | otherwise -> never (VSigma _ d r, VSigma _ d' r') -> solve $ exists "p" (vId VType d d') $ \p -> forAll Ex "x" d $ \x -> vId VType (r $$ x) (r' $$ vCoe d d' p x) (VNe _ _, _) -> stuck (_, VNe _ _) -> stuck _ -> never VTop -> always VPi i t dom cod -> solve $ forAll i t dom \vl -> vId (cod $$ vl) (vApp a i vl) (vApp b i vl) VSigma t dom cod -> -- a = (x, p) -- b = (y, q) -- (a, b) ≡ (c, d) : (x : A) * P x -- ~> (path : a == c) * coe (cong A Type P path) b == d let x = vProj1 a y = vProj1 b p = vProj2 a q = vProj2 b in solve $ exists t (vId dom x y) $ \pr -> vId (cod $$ y) (vCoe (cod $$ x) (cod $$ y) (vCong dom VType x y (function Ex (T.pack "x") (cod $$)) pr) p) q VEq{} -> solve VTop _ -> stuck vBottom :: Value vBottom = forAll Im "A" VType id vCoe :: VTy -> VTy -> Value -> Value -> Value -- vCoe _ _ (VGlued HRefl _ _) element = element vCoe (VPi i _ d r) ty2@(VPi i' _ d' r') p f | i /= i' = vApp p Ex ty2 | otherwise = function i "x" $ \x -> let p1 = vProj1 p -- d == d' p2 = vProj2 p -- (x : A) -> r x == r' (coe p1 x) x0 = vCoe d' d (vSym VType d d' p1) x in vCoe (r $$ x0) (r' $$ x) (vApp p2 Ex x0) (vApp f i x0) vCoe tyA tyB proof element = splitFibration tyA tyB $ VGlued HCoe (Seq.fromList spine) Nothing where spine = [AppIm tyA, AppIm tyB, AppEx proof, AppEx element] -- Types are split fibrations -- coe {A} {A} p x = x even when p /= refl splitFibration tA tB vstuck = unsafeDupablePerformIO $ do old <- readMVar elabMetas t <- runElab (unify tA tB) emptyElabState case t of Left _ -> do swapMVar elabMetas old pure vstuck Right _ -> pure element vCong :: Value -> Value -> Value -> Value -> Value -> Value -> Value vCong _a c _x _y g (force -> VGlued HCong (toList -> [AppIm a, AppIm _b, AppIm x, AppIm y, AppEx f, AppEx p]) _) = VGlued HCong (Seq.fromList [AppIm a, AppIm c, AppIm x, AppIm y, AppEx (function Ex "x" (vApp g Ex . vApp f Ex)), AppEx p]) Nothing vCong _a b _x _ f (force -> VGlued HRefl (toList -> [AppIm _, AppIm x]) _) = VGlued HRefl (Seq.fromList [AppIm b, AppIm (vApp f Ex x)]) Nothing vCong a b x y f p = VGlued HCong (Seq.fromList [AppIm a, AppIm b, AppIm x, AppIm y, AppEx f, AppEx p]) Nothing vSym :: Value -> Value -> Value -> Value -> Value vSym a _ y (VGlued HRefl _ Nothing) = VGlued HRefl (Seq.fromList [AppIm a, AppIm y]) Nothing vSym _ _ _ (VGlued HSym (toList -> [_a, _y, _x, AppEx p]) Nothing) = p vSym a x y p = VGlued HSym (Seq.fromList [AppIm a, AppIm x, AppIm y, AppEx p]) Nothing vApp :: HasCallStack => Value -> Plicity -> Value -> Value vApp (VGlued x s v) p r = VGlued x (s Seq.|> thing) (fmap (\v -> vApp v p r) v) where thing = case p of Ex -> AppEx r Im -> AppIm r vApp (VLam _ _ c) _ a = c $$ a vApp _fun _plic _arg = error "invalid application" vProj1 :: Value -> Value vProj1 (VPair a _) = a vProj1 x = VProj1 x vProj2 :: Value -> Value vProj2 (VPair _ a) = a vProj2 x = VProj2 x ($$) :: HasCallStack => Closure -> Value -> Value Closure e t $$ v = evaluate e' t where e' = e { locals = v Seq.:<| locals e } ClMeta (MetaFun f) $$ v = f v forAll :: Plicity -> T.Text -> Value -> (Value -> Value) -> Value forAll i t d = VPi i t d . ClMeta . MetaFun exists :: T.Text -> Value -> (Value -> Value) -> Value exists t d = VSigma t d . ClMeta . MetaFun function :: Plicity -> T.Text -> (Value -> Value) -> Value function i t = VLam i t . ClMeta . MetaFun quote :: HasCallStack => Level -> Value -> Term quote _ VType = Type quote l (VPi p t d r) = Pi p t (quote l d) (quote (succ l) (r $$ vVar (Bound (unLvl l)))) quote l (VLam p t b) = Lam p t (quote (succ l) (b $$ vVar (Bound (unLvl l)))) quote l (VSigma t d r) = Sigma t (quote l d) (quote (succ l) (r $$ vVar (Bound (unLvl l)))) quote l (VPair a b) = Pair (quote l a) (quote l b) quote l (VProj1 a) = Proj1 (quote l a) quote l (VProj2 a) = Proj2 (quote l a) quote _ VTop = Top quote _ VUnit = Unit quote l (VEq a b c) = Id (quote l a) (quote l b) (quote l c) -- quote l (VEqG _ _ _ d) = quote l d quote l (VEqG a b c _) = Id (quote l a) (quote l b) (quote l c) quote l (VGlued v s _) = foldl app v' s where v' = case v of HVar (Bound i) -> Bv (lvl2Ix l (Lvl i)) HCon t -> Con t HMeta m -> Meta m HRefl -> Refl HCoe -> Coe HCong -> Cong HSym -> Sym app f (AppEx t) = App Ex f (quote l t) app f (AppIm t) = App Im f (quote l t) app f SProj1 = Proj1 f app f SProj2 = Proj2 f force :: Value -> Value force = unsafeDupablePerformIO . go where go stuck@(VGlued (HMeta (MV m)) sp Nothing) = do t <- readMVar elabMetas case IntMap.lookup m t of Just (Solved vl) -> go $ foldl vAppSp vl sp _ -> pure stuck go (VGlued _ _ (Just vl)) = go vl go x = pure x vAppSp :: Value -> SpineThing -> Value vAppSp vl (AppEx f) = vApp vl Ex f vAppSp vl (AppIm f) = vApp vl Im f vAppSp vl SProj1 = vProj1 vl vAppSp vl SProj2 = vProj2 vl zonk :: Value -> Value zonk (VLam vis var body) = VLam vis var (ClMeta (MetaFun (\v -> zonk (body $$ v)))) zonk (VPi vis var dom body) = VPi vis var (zonk dom) (ClMeta (MetaFun (\v -> zonk (body $$ v)))) zonk (VSigma var dom body) = VSigma var (zonk dom) (ClMeta (MetaFun (\v -> zonk (body $$ v)))) zonk t = everywhere (mkT force) t unify :: VTy -> VTy -> ElabM () unify a b = asks elabLevel >>= flip go (a, b) where go, go' :: Level -> (VTy, VTy) -> ElabM () go' l (VGlued h sp x, VGlued h' sp' y) | h == h' = goSpine l sp sp' | Just x <- x, Just y <- y = go l (x, y) -- flexible head (solve meta) go' l (VGlued (HMeta m) sp _, y) = solveMeta m sp y go' _ (x, VGlued (HMeta m) sp _) = solveMeta m sp x -- rigid heads (compare unfolding) go' l (VGlued _ _ (Just x), y) = go l (x, y) go' l (x, VGlued _ _ (Just y)) = go l (x, y) go' _ (VType, VType) = pure () go' _ (VTop, VTop) = pure () go' _ (VUnit, VUnit) = pure () go' l (VPi i _ d r, VPi i' _ d' r') | i == i' = do go l (d, d') let i = unLvl l go (succ l) (r $$ vVar (Bound i), r' $$ vVar (Bound i)) go' l (VSigma _ d r, VSigma _ d' r') = do go l (d, d') let i = unLvl l go (succ l) (r $$ vVar (Bound i), r' $$ vVar (Bound i)) go' l (VLam i _ r, VLam i' _ r') | i == i' = do let i = unLvl l go (succ l) (r $$ vVar (Bound i), r' $$ vVar (Bound i)) go' l (VLam p _ r, t) = do let i = unLvl l go (succ l) (r $$ vVar (Bound i), vApp t p (vVar (Bound i))) go' l (r, VLam p _ t) = do let i = unLvl l go (succ l) (vApp r p (vVar (Bound i)), t $$ vVar (Bound i)) go' l (VEqG a b c _, VEqG a' b' c' _) = go l (a, a') *> go l (b, b') *> go l (c, c') go' l (VEq a b c, VEqG a' b' c' _) = go l (a, a') *> go l (b, b') *> go l (c, c') go' l (VEqG a b c _, VEq a' b' c') = go l (a, a') *> go l (b, b') *> go l (c, c') go' l (VEq a b c, VEq a' b' c') = go l (a, a') *> go l (b, b') *> go l (c, c') go' l (VEqG _ _ _ a, b) = go l (a, b) go' l (a, VEqG _ _ _ b) = go l (a, b) go' l (VProj1 a, VProj1 b) = go l (a, b) go' l (VProj2 a, VProj2 b) = go l (a, b) go' l (VPair a b, VPair a' b') = go l (a, a') >> go l (b, b') go' l (a, b) = do ns <- getNames typeError (NotEqual ns (quote l a) (quote l b)) go l (a, b) = go' l (force a, force b) goSpine _ Seq.Empty Seq.Empty = pure () goSpine l (AppEx x Seq.:<| xs) (AppEx y Seq.:<| ys) = do go l (x, y) goSpine l xs ys goSpine l (AppIm x Seq.:<| xs) (AppIm y Seq.:<| ys) = do go l (x, y) goSpine l xs ys goSpine l (x Seq.:<| xs) (y Seq.:<| ys) | x == y = goSpine l xs ys goSpine l _ _ = do ns <- getNames typeError (NotEqual ns (quote l a) (quote l b)) solveMeta :: HasCallStack => MetaVar -> Seq.Seq SpineThing -> VTy -> ElabM () solveMeta (MV meta) spine rhs = do level <- asks elabLevel pren <- invert level spine rhs <- rename (MV meta) pren rhs let solution = evaluate emptyEnv (lams (dom pren) rhs) -- need to deepSeq solutions here -- no deepSeq? no problem liftIO $ Exc.evaluate (length (show solution)) liftIO . modifyMVar_ elabMetas $ pure . IntMap.insert meta (Solved solution) `catchError` \case [] -> do level <- asks elabLevel names <- getNames typeError (CantSolveMeta names (quote level (VGlued (HMeta (MV meta)) spine Nothing)) (quote level rhs)) cs -> throwError cs elabMetas :: MVar (IntMap.IntMap Meta) elabMetas = unsafeDupablePerformIO (newMVar mempty) {-# NOINLINE elabMetas #-} lams :: Level -> Term -> Term lams l = go (Lvl 0) where go x t | x == l = t go x t = Lam Ex (T.pack ("x" ++ show (unLvl x))) $ go (succ x) t data PartialRen = PRen { dom :: {-# UNPACK #-} !Level , rng :: {-# UNPACK #-} !Level , sub :: IntMap.IntMap Level } deriving (Eq, Show, Ord) liftRen :: PartialRen -> PartialRen liftRen (PRen d r s) = PRen (succ d) (succ r) (IntMap.insert (unLvl r) d s) invert :: Level -> Seq.Seq SpineThing -> ElabM PartialRen invert gamma spine = do (dom, ren) <- go spine pure (PRen dom gamma ren) where go Seq.Empty = pure (Lvl 0, mempty) go (sp Seq.:|> AppEx t) = do (dom, ren) <- go sp case force t of VGlued (HVar (Bound l)) Seq.Empty _ | IntMap.notMember l ren -> pure (succ dom, IntMap.insert l dom ren) _ -> throwError [] go (_ Seq.:|> _) = throwError [] rename :: HasCallStack => MetaVar -> PartialRen -> Value -> ElabM Term rename meta pren = go pren where go :: HasCallStack => PartialRen -> Value -> ElabM Term go pren (VGlued (HMeta m) sp _) | m == meta = throwError [] | otherwise = goSp pren (Meta m) sp go pren (VGlued (HVar (Bound m)) sp _) = case IntMap.lookup m (sub pren) of Just v -> goSp pren (Bv (lvl2Ix (dom pren) v)) sp Nothing -> throwError [] go pren (VGlued h sp _) = goHead h >>= \h -> goSp pren h sp where goHead HRefl = pure Refl goHead HCong = pure Cong goHead HCoe = pure Coe goHead HSym = pure Sym go pren (VPi p t d r) = Pi p t <$> go pren d <*> go (liftRen pren) (r $$ vVar (Bound (unLvl (rng pren)))) go pren (VLam p t x) = Lam p t <$> go (liftRen pren) (x $$ vVar (Bound (unLvl (rng pren)))) go _ VType = pure Type go _ VTop = pure Top go _ VUnit = pure Unit go pren (VSigma t d r) = Sigma t <$> go pren d <*> go (liftRen pren) (r $$ vVar (Bound (unLvl (rng pren)))) go pren (VPair a b) = Pair <$> go pren a <*> go pren b go pren (VProj1 a) = Proj1 <$> go pren a go pren (VProj2 a) = Proj2 <$> go pren a go pren (VEq a b c) = Id <$> go pren a <*> go pren b <*> go pren c go pren (VEqG _ _ _ d) = go pren d -- go pren x = error (show x) goSp _ t Seq.Empty = pure t goSp pren t (sp Seq.:|> AppEx tm) = App Ex <$> goSp pren t sp <*> go pren tm goSp pren t (sp Seq.:|> AppIm tm) = App Im <$> goSp pren t sp <*> go pren tm goSp pren t (sp Seq.:|> SProj1) = Proj1 <$> goSp pren t sp goSp pren t (sp Seq.:|> SProj2) = Proj2 <$> goSp pren t sp