less prototype, less bad code implementation of CCHM type theory
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
9.3 KiB

  1. {-# LANGUAGE TupleSections #-}
  2. {-# LANGUAGE DeriveAnyClass #-}
  3. {-# LANGUAGE ScopedTypeVariables #-}
  4. module Elab where
  5. import Control.Monad.Reader
  6. import Control.Exception
  7. import qualified Data.Map.Strict as Map
  8. import Data.Traversable
  9. import Data.Typeable
  10. import Data.Foldable
  11. import Elab.Eval.Formula (possible)
  12. import Elab.WiredIn
  13. import Elab.Monad
  14. import Elab.Eval
  15. import qualified Presyntax.Presyntax as P
  16. import Prettyprinter
  17. import Syntax
  18. import Syntax.Pretty
  19. import qualified Data.Text as T
  20. infer :: P.Expr -> ElabM (Term, NFType)
  21. infer (P.Span ex a b) = withSpan a b $ infer ex
  22. infer (P.Var t) = do
  23. name <- getNameFor t
  24. nft <- getNfType name
  25. pure (Ref name, nft)
  26. infer (P.App p f x) = do
  27. (f, f_ty) <- infer f
  28. porp <- isPiType p f_ty
  29. case porp of
  30. It'sProd d r w -> do
  31. x <- check x d
  32. x_nf <- eval x
  33. pure (App p (w f) x, r x_nf)
  34. It'sPath li le ri wp -> do
  35. x <- check x VI
  36. x_nf <- eval x
  37. pure (IElim (quote (fun li)) (quote le) (quote ri) (wp f) x, li x_nf)
  38. It'sPartial phi a w -> do
  39. x <- check x (VIsOne phi)
  40. pure (App P.Ex (w f) x, a)
  41. It'sPartialP phi a w -> do
  42. x <- check x (VIsOne phi)
  43. x_nf <- eval x
  44. pure (App P.Ex (w f) x, a @@ x_nf)
  45. infer (P.Bracket ex) = do
  46. nm <- getNameFor (T.pack "IsOne")
  47. ty <- getNfType nm
  48. porp <- isPiType P.Ex ty
  49. case porp of
  50. It'sProd d r w -> do
  51. t <- check ex d
  52. t_nf <- eval t
  53. pure (App P.Ex (w (Ref nm)) t, r t_nf)
  54. _ -> do
  55. d <- newMeta VType
  56. r <- newMeta VType
  57. throwElab $ NotEqual ty (VPi P.Ex d (Closure (T.pack "x") (const r)))
  58. infer (P.Proj1 x) = do
  59. (tm, ty) <- infer x
  60. (d, _, wp) <- isSigmaType ty
  61. pure (Proj1 (wp tm), d)
  62. infer (P.Proj2 x) = do
  63. (tm, ty) <- infer x
  64. tm_nf <- eval tm
  65. (_, r, wp) <- isSigmaType ty
  66. pure (Proj2 (wp tm), r (vProj1 tm_nf))
  67. infer exp = do
  68. t <- newMeta VType
  69. tm <- switch $ check exp t
  70. pure (tm, t)
  71. check :: P.Expr -> NFType -> ElabM Term
  72. check (P.Span ex a b) ty = withSpan a b $ check ex ty
  73. check (P.Lam p var body) (VPi p' dom (Closure _ rng)) | p == p' =
  74. assume (Bound var) dom $
  75. Lam p var <$> check body (rng (VVar (Bound var)))
  76. check tm (VPi P.Im dom (Closure var rng)) =
  77. assume (Bound var) dom $
  78. Lam P.Im var <$> check tm (rng (VVar (Bound var)))
  79. check (P.Lam p v b) ty = do
  80. porp <- isPiType p =<< forceIO ty
  81. case porp of
  82. It'sProd d r wp ->
  83. assume (Bound v) d $
  84. wp . Lam p v <$> check b (r (VVar (Bound v)))
  85. It'sPath li le ri wp -> do
  86. tm <- assume (Bound v) VI $
  87. Lam P.Ex v <$> check b (force (li (VVar (Bound v))))
  88. tm_nf <- eval tm
  89. unify (tm_nf @@ VI0) le
  90. `catchElab` (throwElab . WhenCheckingEndpoint le ri VI0)
  91. unify (tm_nf @@ VI1) ri
  92. `catchElab` (throwElab . WhenCheckingEndpoint le ri VI1)
  93. pure (wp (PathIntro (quote (fun li)) tm))
  94. It'sPartial phi a wp ->
  95. assume (Bound v) (VIsOne phi) $
  96. wp . Lam p v <$> check b a
  97. It'sPartialP phi a wp ->
  98. assume (Bound v) (VIsOne phi) $
  99. wp . Lam p v <$> check b (a @@ VVar (Bound v))
  100. check (P.Pair a b) ty = do
  101. (d, r, wp) <- isSigmaType =<< forceIO ty
  102. a <- check a d
  103. a_nf <- eval a
  104. b <- check b (r a_nf)
  105. pure (wp (Pair a b))
  106. check (P.Pi p s d r) ty = do
  107. isSort ty
  108. d <- check d ty
  109. d_nf <- eval d
  110. assume (Bound s) d_nf $ do
  111. r <- check r ty
  112. pure (Pi p s d r)
  113. check (P.Sigma s d r) ty = do
  114. isSort ty
  115. d <- check d ty
  116. d_nf <- eval d
  117. assume (Bound s) d_nf $ do
  118. r <- check r ty
  119. pure (Sigma s d r)
  120. check (P.LamSystem bs) ty = do
  121. (extent, dom) <- isPartialType ty
  122. eqns <- for (zip [(0 :: Int)..] bs) $ \(n, (formula, rhs)) -> do
  123. formula <- checkFormula formula
  124. rhs <- check rhs dom
  125. pure (n, (formula, rhs))
  126. unify extent (foldl ior VI0 (map (fst . snd) eqns))
  127. for_ eqns $ \(n, (formula, rhs)) ->
  128. for_ eqns $ \(n', (formula', rhs')) -> do
  129. let truth = possible mempty (iand formula formula')
  130. when ((n /= n') && fst truth) $ do
  131. vl <- eval rhs
  132. vl' <- eval rhs'
  133. unify vl vl'
  134. `withNote` vsep [ pretty "These two cases must agree because they are both possible:"
  135. , indent 2 $ pretty '*' <+> prettyTm (quote formula) <+> operator (pretty "=>") <+> prettyTm rhs
  136. , indent 2 $ pretty '*' <+> prettyTm (quote formula') <+> operator (pretty "=>") <+> prettyTm rhs'
  137. ]
  138. `withNote` (pretty "Consider this face, where both are true:" <+> showFace (snd truth))
  139. name <- newName
  140. pure (Lam P.Ex name (System (Map.fromList (map (\(_, (x, y)) -> (quote x, y)) eqns))))
  141. check exp ty = do
  142. (tm, has) <- switch $ infer exp
  143. wp <- isConvertibleTo has ty
  144. pure (wp tm)
  145. checkFormula :: P.Formula -> ElabM Value
  146. checkFormula P.FTop = pure VI1
  147. checkFormula P.FBot = pure VI0
  148. checkFormula (P.FAnd x y) = iand <$> checkFormula x <*> checkFormula y
  149. checkFormula (P.FOr x y) = ior <$> checkFormula x <*> checkFormula y
  150. checkFormula (P.FIs0 x) = do
  151. nm <- getNameFor x
  152. ty <- getNfType nm
  153. unify ty VI
  154. pure (inot (VVar nm))
  155. checkFormula (P.FIs1 x) = do
  156. nm <- getNameFor x
  157. ty <- getNfType nm
  158. unify ty VI
  159. pure (VVar nm)
  160. isSort :: NFType -> ElabM ()
  161. isSort VType = pure ()
  162. isSort VTypeω = pure ()
  163. isSort vt@(VNe HMeta{} _) = unify vt VType
  164. isSort vt = liftIO . throwIO $ NotEqual vt VType
  165. data ProdOrPath
  166. = It'sProd { prodDmn :: NFType
  167. , prodRng :: NFType -> NFType
  168. , prodWrap :: Term -> Term
  169. }
  170. | It'sPath { pathLine :: NFType -> NFType
  171. , pathLeft :: Value
  172. , pathRight :: Value
  173. , pathWrap :: Term -> Term
  174. }
  175. | It'sPartial { partialExtent :: NFEndp
  176. , partialDomain :: Value
  177. , partialWrap :: Term -> Term
  178. }
  179. | It'sPartialP { partialExtent :: NFEndp
  180. , partialDomain :: Value
  181. , partialWrap :: Term -> Term
  182. }
  183. isPiType :: P.Plicity -> NFType -> ElabM ProdOrPath
  184. isPiType p (VPi p' d (Closure _ k)) | p == p' = pure (It'sProd d k id)
  185. isPiType P.Ex (VPath li le ri) = pure (It'sPath (li @@) le ri id)
  186. isPiType P.Ex (VPartial phi a) = pure (It'sPartial phi a id)
  187. isPiType P.Ex (VPartialP phi a) = pure (It'sPartialP phi a id)
  188. isPiType P.Ex (VPi P.Im d (Closure _ k)) = do
  189. meta <- newMeta d
  190. porp <- isPiType P.Ex (k meta)
  191. pure $ case porp of
  192. It'sProd d r w -> It'sProd d r (\f -> w (App P.Im f (quote meta)))
  193. It'sPath l x y w -> It'sPath l x y (\f -> w (App P.Im f (quote meta)))
  194. It'sPartial phi a w -> It'sPartial phi a (\f -> w (App P.Im f (quote meta)))
  195. It'sPartialP phi a w -> It'sPartialP phi a (\f -> w (App P.Im f (quote meta)))
  196. isPiType p t = do
  197. dom <- newMeta VType
  198. name <- newName
  199. assume (Bound name) dom $ do
  200. rng <- newMeta VType
  201. wp <- isConvertibleTo t (VPi p dom (Closure name (const rng)))
  202. pure (It'sProd dom (const rng) wp)
  203. isSigmaType :: NFType -> ElabM (Value, NFType -> NFType, Term -> Term)
  204. isSigmaType (VSigma d (Closure _ k)) = pure (d, k, id)
  205. isSigmaType t = do
  206. dom <- newMeta VType
  207. name <- newName
  208. assume (Bound name) dom $ do
  209. rng <- newMeta VType
  210. wp <- isConvertibleTo t (VSigma dom (Closure name (const rng)))
  211. pure (dom, const rng, wp)
  212. isPartialType :: NFType -> ElabM (NFEndp, Value)
  213. isPartialType (VPartial phi a) = pure (phi, a)
  214. isPartialType (VPartialP phi a) = pure (phi, a)
  215. isPartialType t = do
  216. phi <- newMeta VI
  217. dom <- newMeta (VPartial phi VType)
  218. unify t (VPartial phi dom)
  219. pure (phi, dom)
  220. checkStatement :: P.Statement -> ElabM a -> ElabM a
  221. checkStatement (P.SpanSt s a b) k = withSpan a b $ checkStatement s k
  222. checkStatement (P.Decl name ty) k = do
  223. ty <- check ty VTypeω
  224. ty_nf <- eval ty
  225. assumes (Defined <$> name) ty_nf k
  226. checkStatement (P.Defn name rhs) k = do
  227. ty <- asks (Map.lookup (Defined name) . getEnv)
  228. case ty of
  229. Nothing -> do
  230. (tm, ty) <- infer rhs
  231. tm_nf <- eval tm
  232. define (Defined name) ty tm_nf k
  233. Just (ty_nf, nm) -> do
  234. case nm of
  235. VVar (Defined n') | n' == name -> pure ()
  236. _ -> liftIO . throwIO $ Redefinition (Defined name)
  237. rhs <- check rhs ty_nf
  238. rhs_nf <- eval rhs
  239. define (Defined name) ty_nf rhs_nf k
  240. checkStatement (P.Builtin winame var) k = do
  241. wi <-
  242. case Map.lookup winame wiredInNames of
  243. Just wi -> pure wi
  244. _ -> liftIO . throwIO $ NoSuchPrimitive winame
  245. let
  246. check = do
  247. nm <- getNameFor var
  248. ty <- getNfType nm
  249. unify ty (wiType wi)
  250. `withNote` hsep [ pretty "Previous definition of", pretty nm, pretty "here" ]
  251. `seeAlso` nm
  252. env <- ask
  253. liftIO $
  254. runElab check env `catch` \(_ :: NotInScope) -> pure ()
  255. define (Defined var) (wiType wi) (wiValue wi) k
  256. checkStatement (P.ReplNf e) k = do
  257. (e, _) <- infer e
  258. e_nf <- eval e
  259. h <- asks commHook
  260. liftIO (h e_nf)
  261. k
  262. checkStatement (P.ReplTy e) k = do
  263. (_, ty) <- infer e
  264. h <- asks commHook
  265. liftIO (h ty)
  266. k
  267. checkProgram :: [P.Statement] -> ElabM a -> ElabM a
  268. checkProgram [] k = k
  269. checkProgram (st:sts) k = checkStatement st $ checkProgram sts k
  270. newtype Redefinition = Redefinition { getRedefName :: Name }
  271. deriving (Show, Typeable, Exception)
  272. data WhenCheckingEndpoint = WhenCheckingEndpoint { leftEndp :: Value, rightEndp :: Value, whichIsWrong :: NFEndp, exc :: SomeException }
  273. deriving (Show, Typeable, Exception)