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.

201 lines
5.7 KiB

  1. {-# LANGUAGE LambdaCase #-}
  2. {-# LANGUAGE DeriveAnyClass #-}
  3. module Elab.Eval where
  4. import Control.Monad.Reader
  5. import Control.Exception
  6. import qualified Data.Map.Strict as Map
  7. import qualified Data.Set as Set
  8. import qualified Data.Text as T
  9. import Data.Traversable
  10. import Data.Set (Set)
  11. import Data.Typeable
  12. import Data.Foldable
  13. import Data.IORef
  14. import Data.Maybe
  15. import Elab.Monad
  16. import Presyntax.Presyntax (Plicity(..))
  17. import Syntax
  18. import System.IO.Unsafe
  19. eval :: Term -> ElabM Value
  20. eval t = asks (flip evalWithEnv t)
  21. forceIO :: MonadIO m => Value -> m Value
  22. forceIO vl@(VNe (HMeta (MV _ cell)) args) = do
  23. solved <- liftIO $ readIORef cell
  24. case solved of
  25. Just vl -> forceIO $ foldl applProj vl (reverse args)
  26. Nothing -> pure vl
  27. forceIO x = pure x
  28. applProj :: Value -> Projection -> Value
  29. applProj fun (PApp p arg) = vApp p fun arg
  30. applProj fun PProj1 = vProj1 fun
  31. applProj fun PProj2 = vProj2 fun
  32. force :: Value -> Value
  33. force = unsafePerformIO . forceIO
  34. evalWithEnv :: ElabEnv -> Term -> Value
  35. evalWithEnv env (Ref x) =
  36. case Map.lookup x (getEnv env) of
  37. Just (_, vl) -> vl
  38. _ -> error "variable not in scope when evaluating"
  39. evalWithEnv env (App p f x) = vApp p (evalWithEnv env f) (evalWithEnv env x)
  40. evalWithEnv env (Lam p s t) =
  41. VLam p $ Closure s $ \a ->
  42. evalWithEnv (ElabEnv (Map.insert (Bound s) (error "type of abs", a) (getEnv env))) t
  43. evalWithEnv env (Pi p s d t) =
  44. VPi p (evalWithEnv env d) $ Closure s $ \a ->
  45. evalWithEnv (ElabEnv (Map.insert (Bound s) (error "type of abs", a) (getEnv env))) t
  46. evalWithEnv _ (Meta m) = VNe (HMeta m) []
  47. evalWithEnv env (Sigma s d t) =
  48. VSigma (evalWithEnv env d) $ Closure s $ \a ->
  49. evalWithEnv (ElabEnv (Map.insert (Bound s) (error "type of abs", a) (getEnv env))) t
  50. evalWithEnv e (Pair a b) = VPair (evalWithEnv e a) (evalWithEnv e b)
  51. evalWithEnv e (Proj1 a) = vProj1 (evalWithEnv e a)
  52. evalWithEnv e (Proj2 a) = vProj2 (evalWithEnv e a)
  53. evalWithEnv _ Type = VType
  54. vApp :: Plicity -> Value -> Value -> Value
  55. vApp p (VLam p' k) arg = assert (p == p') $ clCont k arg
  56. vApp p (VNe h sp) arg = VNe h (PApp p arg:sp)
  57. vApp _ x _ = error $ "can't apply " ++ show x
  58. vProj1 :: Value -> Value
  59. vProj1 (VPair a _) = a
  60. vProj1 (VNe h sp) = VNe h (PProj1:sp)
  61. vProj1 x = error $ "can't proj1 " ++ show x
  62. vProj2 :: Value -> Value
  63. vProj2 (VPair _ b) = b
  64. vProj2 (VNe h sp) = VNe h (PProj2:sp)
  65. vProj2 x = error $ "can't proj2 " ++ show x
  66. data NotEqual = NotEqual Value Value
  67. deriving (Show, Typeable, Exception)
  68. unify :: Value -> Value -> ElabM ()
  69. unify topa topb = join $ go <$> forceIO topa <*> forceIO topb where
  70. go (VNe (HMeta mv) sp) rhs = solveMeta mv sp rhs
  71. go (VNe x a) (VNe x' a')
  72. | x == x', length a == length a' =
  73. traverse_ (uncurry unifySpine) (zip a a')
  74. | otherwise = fail
  75. go (VLam p (Closure _ k)) (VLam p' (Closure _ k')) | p == p' = do
  76. t <- VVar . Bound <$> newName
  77. unify (k t) (k' t)
  78. go (VPi p d (Closure _ k)) (VPi p' d' (Closure _ k')) | p == p' = do
  79. t <- VVar . Bound <$> newName
  80. unify d d'
  81. unify (k t) (k' t)
  82. go _ _ = fail
  83. fail = liftIO . throwIO $ NotEqual topa topb
  84. unifySpine (PApp a v) (PApp a' v')
  85. | a == a' = unify v v'
  86. unifySpine _ _ = fail
  87. isConvertibleTo :: Value -> Value -> ElabM (Term -> Term)
  88. VPi Im d (Closure _v k) `isConvertibleTo` ty = do
  89. meta <- newMeta d
  90. cont <- k meta `isConvertibleTo` ty
  91. pure (\f -> cont (App Ex f (quote meta)))
  92. isConvertibleTo a b = do
  93. unify a b
  94. pure id
  95. newMeta :: Value -> ElabM Value
  96. newMeta _dom = do
  97. n <- newName
  98. c <- liftIO $ newIORef Nothing
  99. let m = MV n c
  100. env <- asks getEnv
  101. t <- for (Map.toList env) $ \(n, (_, c)) -> pure $
  102. case c of
  103. VVar n' | n == n' -> Just (PApp Ex (VVar n'))
  104. _ -> Nothing
  105. pure (VNe (HMeta m) (catMaybes t))
  106. newName :: MonadIO m => m T.Text
  107. newName = liftIO $ do
  108. x <- atomicModifyIORef _nameCounter $ \x -> (x + 1, x + 1)
  109. pure (T.pack (show x))
  110. _nameCounter :: IORef Int
  111. _nameCounter = unsafePerformIO $ newIORef 0
  112. {-# NOINLINE _nameCounter #-}
  113. solveMeta :: MV -> [Projection] -> Value -> ElabM ()
  114. solveMeta m@(MV _ cell) sp rhs = do
  115. liftIO $ print (m, sp, rhs)
  116. names <- checkSpine Set.empty sp
  117. checkScope (Set.fromList (Bound <$> names)) rhs
  118. let tm = quote rhs
  119. lam = evalWithEnv emptyEnv $ foldr (Lam Ex) tm names
  120. liftIO . atomicModifyIORef' cell $ \case
  121. Just _ -> error "filled cell in solvedMeta"
  122. Nothing -> (Just lam, ())
  123. checkScope :: Set Name -> Value -> ElabM ()
  124. checkScope scope (VNe h sp) =
  125. do
  126. case h of
  127. HVar v ->
  128. unless (v `Set.member` scope) . liftIO . throwIO $
  129. NotInScope v
  130. HMeta{} -> pure ()
  131. traverse_ checkProj sp
  132. where
  133. checkProj (PApp _ t) = checkScope scope t
  134. checkProj PProj1 = pure ()
  135. checkProj PProj2 = pure ()
  136. checkScope scope (VLam _ (Closure n k)) =
  137. checkScope (Set.insert (Bound n) scope) (k (VVar (Bound n)))
  138. checkScope scope (VPi _ d (Closure n k)) = do
  139. checkScope scope d
  140. checkScope (Set.insert (Bound n) scope) (k (VVar (Bound n)))
  141. checkScope scope (VSigma d (Closure n k)) = do
  142. checkScope scope d
  143. checkScope (Set.insert (Bound n) scope) (k (VVar (Bound n)))
  144. checkScope s (VPair a b) = traverse_ (checkScope s) [a, b]
  145. checkScope _ VType = pure ()
  146. checkSpine :: Set Name -> [Projection] -> ElabM [T.Text]
  147. checkSpine scope (PApp Ex (VVar n@(Bound t)):xs)
  148. | n `Set.member` scope = liftIO . throwIO $ NonLinearSpine n
  149. | otherwise = (t:) <$> checkSpine scope xs
  150. checkSpine _ (p:_) = liftIO . throwIO $ SpineProj p
  151. checkSpine _ [] = pure []
  152. newtype NonLinearSpine = NonLinearSpine { getDupeName :: Name }
  153. deriving (Show, Typeable, Exception)
  154. newtype SpineProjection = SpineProj { getSpineProjection :: Projection }
  155. deriving (Show, Typeable, Exception)