Prototype, extremely bad code implementation of CCHM Cubical 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.
 

151 lines
5.0 KiB

{-# LANGUAGE LambdaCase #-}
module Main where
import Control.Monad.IO.Class
import Control.Monad.Catch
import qualified Data.Map.Strict as Map
import Data.List
import Elab
import Eval (eval, UnifyError (..))
import Presyntax.Parser
import Presyntax
import Syntax
import System.Console.Haskeline (runInputT, defaultSettings, getInputLine)
import System.Exit
import Systems (formulaOfFace, Face)
import System.Environment
showTypeError :: Maybe [String] -> Elab.TypeError -> String
showTypeError lines (NotInScope l_c) = "Variable not in scope: " ++ l_c
showTypeError lines (UnifyError (NotPiType vl)) = "Not a function type: " ++ show vl
showTypeError lines (UnifyError (NotSigmaType vl)) = "Not a sigma type: " ++ show vl
showTypeError lines (UnifyError (Mismatch a b)) =
unlines [ "Types are not equal: "
, " " ++ show (quote a)
, " vs "
, " " ++ show (quote b)
]
showTypeError lines (WrongFaces _ faces) = unlines (map face faces) where
face :: ([Value], Value, Elab.TypeError) -> String
face (ixs, rhs, err) =
"When checking face described by " ++ show ixs ++ ":\n" ++ showTypeError Nothing err
showTypeError lines (InSpan start end err)
| Just lines <- lines, fst start == fst end
= makeRange (lines !! fst start) start end ++ '\n':showTypeError Nothing err
| otherwise = showTypeError Nothing err
showTypeError lines (IncompleteSystem formula extent) =
unlines $
[ "Incomplete system: "
, "it is defined by " ++ show formula
, "but the context mandates extent " ++ show extent ]
showTypeError lines (IncompatibleFaces (fa, ta) (fb, tb) err) =
unlines [ showTypeError lines err
, "while checking that these overlapping faces are compatible:"
, "* " ++ show fa ++ " -> " ++ show ta
, "* " ++ show fb ++ " -> " ++ show tb
]
showTypeError _ x = show x
makeRange :: String -> (Int, Int) -> (Int, Int) -> String
makeRange line (_, sc) (_, ec) = line ++ "\n" ++ replicate (sc + 1) ' ' ++ replicate (ec - sc) '~'
main :: IO ()
main = do
t <- getArgs
case t of
[file] -> Main.check file
_ -> repl
check :: FilePath -> IO ()
check file = do
code <- readFile file
let
ste e = do
putStrLn $ showTypeError (Just (lines code)) e
exitFailure
case parseString body code of
Left e -> print e
Right x -> do
(tm, _) <- infer (Env mempty) x `catch` ste `catch` (ste . UnifyError)
print (eval (Env mempty) tm)
repl :: IO ()
repl = runInputT defaultSettings (go (Env mempty)) where
go env = getInputLine "> " >>= \case
Just i | ":sq " `isPrefixOf` i -> do
case parseString body (replicate 4 ' ' ++ drop 4 i) of
Right exp ->
(do
(tm, ty) <- liftIO $ infer env exp
liftIO $ drawExtent ty (eval env tm)
`catch` \e -> liftIO $ putStrLn (showTypeError (Just [i]) e))
`catch` \e -> liftIO $ print (e :: SomeException)
Left e -> liftIO (print e)
go env
Just i ->
case parseString statement i of
Left e -> liftIO (print e) *> go env
Right (Assume vs) ->
let
loop env ((v, t):vs) = do
tm <- liftIO $ Elab.check env t VTypeω
let ty = eval env tm
loop env{ names = Map.insert v (ty, VVar v) (names env) } vs
loop env [] = go env
in (loop env vs
`catch` \e -> (liftIO $ putStrLn (showTypeError (Just [i]) e)) *> go env)
`catch` \e -> (liftIO $ print (e :: SomeException)) *> go env
Right (Eval v) -> do
liftIO $
(do
(tm, ty) <- infer env v
let v_nf = eval env tm
putStrLn $ show v_nf ++ " : " ++ show ty
`catch` \e -> putStrLn (showTypeError (Just [i]) e))
`catch` \e -> print (e :: SomeException)
go env
Right (Declare n t e) -> do
(do
t <- liftIO $ Elab.check env t VTypeω
let t' = eval env t
b <- liftIO $ Elab.check env e t'
let b' = eval env b
go env{ names = Map.insert n (t', b') (names env) })
`catch` \e -> (liftIO $ putStrLn (showTypeError (Just [i]) e)) *> go env
`catch` \e -> (liftIO $ print (e :: SomeException)) *> go env
Nothing -> pure ()
drawExtent :: Value -> Value -> IO ()
drawExtent ty vl = nicely $ getDirections ty vl where
getDirections :: Value -> Value -> [([(String, Bool)], Value, Value)]
getDirections (VPi _ VI r) (VLam s VI k) =
let trues = getDirections (r VI1) (k VI1)
falses = getDirections (r VI0) (k VI0)
in map (\(p, t, v) -> ((s, True):p, t, v)) trues
++ map (\(p, t, v) -> ((s, False):p, t, v)) falses
getDirections ty t = [([], ty, t)]
nicely :: [([(String, Bool)], Value, Value)] -> IO ()
nicely [] = pure ()
nicely ((bs, ty, el):fcs) = do
putStr . unwords $ theFace bs
putStrLn $ " => " ++ show el ++ " : " ++ show ty
nicely fcs
theFace = map (\(i, b) ->
if b
then "(" ++ i ++ "1)"
else "(" ++ i ++ "0)")