| @ -0,0 +1 @@ | |||
| .stack-work | |||
| @ -0,0 +1,30 @@ | |||
| Copyright Abigail Magalhães (c) 2021 | |||
| All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above | |||
| copyright notice, this list of conditions and the following | |||
| disclaimer in the documentation and/or other materials provided | |||
| with the distribution. | |||
| * Neither the name of Abigail Magalhães nor the names of other | |||
| contributors may be used to endorse or promote products derived | |||
| from this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| @ -0,0 +1 @@ | |||
| # indexed | |||
| @ -0,0 +1,2 @@ | |||
| import Distribution.Simple | |||
| main = defaultMain | |||
| @ -0,0 +1,2 @@ | |||
| cradle: | |||
| stack: | |||
| @ -0,0 +1,34 @@ | |||
| name: indexed | |||
| version: 0.1.0.0 | |||
| -- synopsis: | |||
| -- description: | |||
| homepage: https://github.com/plt-hokusai/indexed#readme | |||
| license: BSD3 | |||
| license-file: LICENSE | |||
| author: Abigail Magalhães | |||
| maintainer: [email protected] | |||
| copyright: 2021 Abigail Magalhães | |||
| category: Web | |||
| build-type: Simple | |||
| cabal-version: >=1.10 | |||
| extra-source-files: README.md | |||
| executable indexed | |||
| hs-source-dirs: src | |||
| main-is: Main.hs | |||
| default-language: Haskell2010 | |||
| build-depends: base >= 4.7 && < 5 | |||
| , mtl | |||
| , text | |||
| , haskeline | |||
| , exceptions | |||
| , containers | |||
| , megaparsec | |||
| other-modules: Syntax | |||
| , Eval | |||
| , Elab | |||
| , Systems | |||
| , Presyntax | |||
| , Presyntax.Parser | |||
| , Presyntax.Lexer | |||
| @ -0,0 +1,288 @@ | |||
| {-# LANGUAGE ViewPatterns #-} | |||
| {-# LANGUAGE LambdaCase #-} | |||
| {-# LANGUAGE BlockArguments #-} | |||
| {-# LANGUAGE TupleSections #-} | |||
| {-# LANGUAGE DeriveAnyClass #-} | |||
| module Elab where | |||
| import Control.Exception | |||
| import qualified Data.Map.Strict as Map | |||
| import Data.Typeable | |||
| import qualified Presyntax as P | |||
| import Syntax | |||
| import Eval | |||
| import Control.Monad | |||
| import Systems | |||
| import Data.Traversable | |||
| import qualified Data.Set as Set | |||
| import Data.Set (Set) | |||
| import Data.Foldable | |||
| data TypeError | |||
| = NotInScope String | |||
| | UnifyError UnifyError | |||
| | WrongFaces Value [([Value], Value, Elab.TypeError)] | |||
| | InSpan (Int, Int) (Int, Int) Elab.TypeError | |||
| | IncompleteSystem P.Formula P.Formula | |||
| | IncompatibleFaces (P.Formula, Term) (P.Formula, Term) Elab.TypeError | |||
| | InvalidSystem (Set Face) (Set Face) | |||
| deriving (Show, Typeable, Exception) | |||
| check :: Env -> P.Exp -> Value -> IO Term | |||
| check env (P.Span s e exp) wants = | |||
| check env exp wants | |||
| `catch` \case | |||
| InSpan s e err -> throwIO $ InSpan s e err | |||
| err -> throwIO $ InSpan s e err | |||
| check env exp (VSub a fm@(toFormula -> Just phi) el) = do | |||
| tm <- check env exp a | |||
| for (addFormula phi env) \env -> | |||
| let tm' = eval env tm | |||
| in unifyTC env tm' el | |||
| pure (InclSub (quote a) (quote fm) (quote el) tm) | |||
| check env (P.Lam s b) expected = do | |||
| expc <- isPiOrPathType expected | |||
| case expc of | |||
| Left (_, d, r) -> do -- function | |||
| bd <- check env { names = Map.insert s (makeValueGluingSub d s) (names env) } b (r (VVar s)) | |||
| pure (Lam s (quote d) bd) | |||
| Right (a, x, y) -> do | |||
| bd <- check env { names = Map.insert s (VI, VVar s) (names env) } b (a @@ VVar s) | |||
| let t = Lam s I bd | |||
| t' = eval env t | |||
| checkBoundary env [s] t' | |||
| [ ([VI0], x) | |||
| , ([VI1], y) | |||
| ] | |||
| pure (PathI (quote a) (quote x) (quote y) s bd) | |||
| check env (P.Let v t d b) expected = do | |||
| ty <- check env t VType | |||
| let ty' = eval env ty | |||
| d <- check env d ty' | |||
| let d' = eval env d | |||
| b <- check env { names = Map.insert v (ty', d') (names env) } b expected | |||
| pure (Let v (quote ty') d b) | |||
| check env (P.Pair a b) expected = do | |||
| (_, fst, snd) <- isSigmaType expected | |||
| a <- check env a fst | |||
| let a' = eval env a | |||
| b <- check env b (snd a') | |||
| pure (Pair a b) | |||
| check env (P.Partial fs) ty = do | |||
| let formula = orFormula (map fst fs) | |||
| (extent, ty) <- isPartialType formula ty | |||
| let ourFaces = Systems.faces formula | |||
| extentFaces = Systems.faces extent | |||
| unless (formula == extent) $ | |||
| throwIO $ IncompleteSystem formula extent | |||
| let range = formulaToTm $ toDNF formula | |||
| rangeTm <- check env range VI | |||
| let rangeTy = eval env rangeTm | |||
| ts <- for fs $ \(fn, tn) -> do | |||
| tms <- for (addFormula fn env) \env -> check env tn ty | |||
| pure (fn, head tms) | |||
| fmap (System . FMap . Map.fromList) $ for ts \(fn, tn) -> do | |||
| for ts \(fm, tm) -> do | |||
| when (possible (fn `P.And` fm)) do | |||
| for_ (addFormula (fn `P.And` fm) env) $ \env -> | |||
| unifyTC (env) (eval env tn) (eval env tm) | |||
| `catch` \e -> throwIO (IncompatibleFaces (fn, tn) (fm, tm) e) | |||
| pure (fn, tn) | |||
| check env exp expected = do | |||
| (term, actual) <- infer env exp | |||
| unifyTC env actual expected | |||
| pure term | |||
| makeValueGluingSub :: Value -> String -> (Value, Value) | |||
| makeValueGluingSub ty@(VSub a phi a0) s = (ty, VOfSub a phi a0 (VVar s)) | |||
| makeValueGluingSub ty s = (ty, VVar s) | |||
| addFormula :: P.Formula -> Env -> [Env] | |||
| addFormula (P.And x y) = addFormula x >=> addFormula y | |||
| addFormula (P.Or x y) = (++) <$> addFormula x <*> addFormula y | |||
| addFormula P.Top = pure | |||
| addFormula P.Bot = const [] | |||
| addFormula (P.Is0 x) = \env -> pure env{ names = Map.insert x (VI, VI0) (names env) } | |||
| addFormula (P.Is1 x) = \env -> pure env{ names = Map.insert x (VI, VI1) (names env) } | |||
| unifyTC :: Env -> Value -> Value -> IO () | |||
| unifyTC env a b = unify env a b `catch` \e -> const (throwIO (UnifyError (Mismatch a b))) (e :: UnifyError) | |||
| checkBoundary :: Env -> [String] -> Value -> [([Value], Value)] -> IO () | |||
| checkBoundary env ns f = finish <=< go where | |||
| go :: [([Value], Value)] -> IO [([Value], Value, Elab.TypeError)] | |||
| go [] = pure [] | |||
| go ((ixs, vl):faces) = do | |||
| let env' = foldr (\(x, t) env -> env { names = Map.insert x t (names env) }) env (zip ns (zip (repeat VI) ixs)) | |||
| t <- try $ unifyTC env' (foldl (@@) f ixs) vl | |||
| case t of | |||
| Right _ -> go faces | |||
| Left e -> ((ixs, vl, e):) <$> go faces | |||
| finish [] = pure () | |||
| finish xs = throwIO $ WrongFaces f xs | |||
| infer :: Env -> P.Exp -> IO (Term, Value) | |||
| infer env (P.Span s e exp) = | |||
| infer env exp | |||
| `catch` \case | |||
| InSpan s e err -> throwIO $ InSpan s e err | |||
| err -> throwIO $ InSpan s e err | |||
| infer env (P.Var s) = | |||
| case Map.lookup s (names env) of | |||
| Just (t, _) -> pure (Var s, t) | |||
| Nothing -> throwIO (NotInScope s) | |||
| infer env (P.App f x) = do | |||
| (fun, ty) <- infer env f | |||
| funt <- isPiOrPathType ty | |||
| case funt of | |||
| Left (_, dom, rng) -> do | |||
| arg <- check env x dom | |||
| let arg' = eval env arg | |||
| pure (App fun arg, rng arg') | |||
| Right (a, ai0, ai1) -> do | |||
| arg <- check env x VI | |||
| let arg' = eval env arg | |||
| pure (PathP (quote a) (quote ai0) (quote ai1) fun arg, a @@ arg') | |||
| infer env (P.Pi s d r) = do | |||
| dom <- check env d VType | |||
| let d' = eval env dom | |||
| rng <- check env { names = Map.insert s (d', VVar s) (names env) } r VType | |||
| pure (Pi s dom rng, VType) | |||
| infer env (P.Sigma s d r) = do | |||
| dom <- check env d VType | |||
| let d' = eval env dom | |||
| rng <- check env { names = Map.insert s (d', VVar s) (names env) } r VType | |||
| pure (Sigma s dom rng, VType) | |||
| infer env P.Type = pure (Type, VType) | |||
| infer env P.I = pure (I, VType) | |||
| infer env P.I0 = pure (I0, VI) | |||
| infer env P.I1 = pure (I1, VI) | |||
| infer env (P.Cut e t) = do | |||
| t <- check env t VType | |||
| let t' = eval env t | |||
| (, t') <$> check env e t' | |||
| infer env (P.IAnd x y) = do | |||
| x <- check env x VI | |||
| y <- check env y VI | |||
| pure (IAnd x y, VI) | |||
| infer env (P.IOr x y) = do | |||
| x <- check env x VI | |||
| y <- check env y VI | |||
| pure (IOr x y, VI) | |||
| infer env P.Path = do | |||
| pure | |||
| ( Lam "A" (quote index_t) $ | |||
| Lam "x" (App (Var "A") I0) $ | |||
| Lam "y" (App (Var "A") I1) $ | |||
| Path (Var "A") (Var "x") (Var "y") | |||
| , VPi "A" index_t \a -> | |||
| VPi "x" (a @@ VI0) \_ -> | |||
| VPi "y" (a @@ VI1) (const VType)) | |||
| infer env P.PartialT = do | |||
| pure | |||
| ( Lam "r" I $ | |||
| Lam "A" Type $ | |||
| Partial (Var "r") (Var "A") | |||
| , VPi "I" VI \i -> | |||
| VPi "A" VType (const VType)) | |||
| infer env P.Comp = do | |||
| let u_t a r = VPi "i" VI \i -> VPartial r (a @@ i) | |||
| pure | |||
| ( Lam "A" (quote index_t) $ | |||
| Lam "phi" I $ | |||
| Lam "u" (quote (u_t (VVar "A") (VVar "r"))) $ | |||
| Lam "a0" (Sub (App (Var "A") I0) (Var "phi") (App (Var "u") I0)) $ | |||
| Comp (Var "A") (Var "phi") (Var "u") (Var "a0") | |||
| , VPi "A" index_t \a -> | |||
| VPi "phi" VI \phi -> | |||
| VPi "u" (u_t a phi) \u -> | |||
| VPi "_" (VSub (a @@ VI0) phi (u @@ VI0)) \_ -> | |||
| a @@ VI1 | |||
| ) | |||
| infer env P.SubT = do | |||
| pure | |||
| ( Lam "A" Type $ | |||
| Lam "phi" I $ | |||
| Lam "u" (Partial (Var "phi") (Var "A")) $ | |||
| Sub (Var "A") (Var "phi") (Var "u") | |||
| , VPi "A" VType \a -> | |||
| VPi "phi" VI \phi -> | |||
| VPi "_" (VPartial phi a) (const VType) | |||
| ) | |||
| infer env (P.INot x) = (, VI) . INot <$> check env x VI | |||
| infer env P.Lam{} = error "can't infer type for lambda" | |||
| infer env (P.Let v t d b) = do | |||
| ty <- check env t VType | |||
| let ty' = eval env ty | |||
| d <- check env d ty' | |||
| let d' = eval env d | |||
| (b, t) <- infer env{ names = Map.insert v (ty', d') (names env) } b | |||
| pure (Let v ty d b, t) | |||
| infer env (P.Proj1 x) = do | |||
| (t, ty) <- infer env x | |||
| (_, d, _) <- isSigmaType ty | |||
| pure (Proj1 t, d) | |||
| infer env (P.Proj2 x) = do | |||
| (t, ty) <- infer env x | |||
| let t' = eval env t | |||
| (_, _, r) <- isSigmaType ty | |||
| pure (Proj2 t, r (proj1 t')) | |||
| formulaToTm :: P.Formula -> P.Exp | |||
| formulaToTm (P.Is0 i) = P.INot (P.Var i) | |||
| formulaToTm (P.Is1 i) = P.Var i | |||
| formulaToTm (P.And x y) = P.IAnd (formulaToTm x) (formulaToTm y) | |||
| formulaToTm (P.Or x y) = P.IOr (formulaToTm x) (formulaToTm y) | |||
| formulaToTm P.Top = P.I1 | |||
| formulaToTm P.Bot = P.I0 | |||
| checkFormula :: Env -> P.Formula -> IO () | |||
| checkFormula env P.Top = pure () | |||
| checkFormula env P.Bot = pure () | |||
| checkFormula env (P.And x y) = checkFormula env x *> checkFormula env y | |||
| checkFormula env (P.Or x y) = checkFormula env x *> checkFormula env y | |||
| checkFormula env (P.Is0 x) = | |||
| case Map.lookup x (names env) of | |||
| Just (ty, _) -> unifyTC env ty VI | |||
| Nothing -> throwIO (NotInScope x) | |||
| checkFormula env (P.Is1 x) = | |||
| case Map.lookup x (names env) of | |||
| Just (ty, _) -> unifyTC env ty VI | |||
| Nothing -> throwIO (NotInScope x) | |||
| index_t :: Value | |||
| index_t = VPi "_" VI (const VType) | |||
| @ -0,0 +1,456 @@ | |||
| {-# LANGUAGE ViewPatterns #-} | |||
| {-# LANGUAGE DeriveAnyClass #-} | |||
| {-# LANGUAGE BlockArguments #-} | |||
| {-# LANGUAGE LambdaCase #-} | |||
| module Eval where | |||
| import Syntax | |||
| import qualified Data.Map.Strict as Map | |||
| import Data.Foldable | |||
| import Control.Exception | |||
| import Data.Typeable | |||
| import System.IO.Unsafe (unsafePerformIO) | |||
| import Data.IORef | |||
| import Systems | |||
| import Presyntax (Formula) | |||
| import qualified Presyntax as P | |||
| import Data.Maybe | |||
| import Debug.Trace | |||
| import GHC.Stack | |||
| iand :: Value -> Value -> Value | |||
| iand = \case | |||
| VI1 -> id | |||
| VI0 -> const VI0 | |||
| x -> \case | |||
| VI0 -> VI0 | |||
| VI1 -> x | |||
| y -> VIAnd x y | |||
| ior :: Value -> Value -> Value | |||
| ior = \case | |||
| VI0 -> id | |||
| VI1 -> const VI1 | |||
| x -> \case | |||
| VI1 -> VI1 | |||
| VI0 -> x | |||
| y -> VIOr x y | |||
| inot :: Value -> Value | |||
| inot VI1 = VI0 | |||
| inot VI0 = VI1 | |||
| inot (VIOr x y) = iand (inot x) (inot y) | |||
| inot (VIAnd x y) = ior (inot x) (inot y) | |||
| inot (VINot x) = x | |||
| inot x = VINot x | |||
| (@@) :: Value -> Value -> Value | |||
| VNe hd xs @@ vl = VNe hd (PApp vl:xs) | |||
| VLam _ _ k @@ vl = k vl | |||
| VEqGlued a b @@ vl = VEqGlued (a @@ vl) (b @@ vl) | |||
| VOfSub a phi u0 x @@ vl = x @@ vl | |||
| f @@ _ = error $ "can't apply argument to " ++ show f | |||
| proj1 :: Value -> Value | |||
| proj1 (VPair x _) = x | |||
| proj1 (VEqGlued x y) = VEqGlued (proj1 x) (proj1 y) | |||
| proj1 (VNe s xs) = VNe s (PProj1:xs) | |||
| proj1 (VOfSub (VSigma _ d _) phi u0 x) = VOfSub d phi (proj1 u0) (proj1 x) | |||
| proj1 x = error $ "can't proj1 " ++ show x | |||
| proj2 :: Value -> Value | |||
| proj2 (VPair _ y) = y | |||
| proj2 (VEqGlued x y) = VEqGlued (proj1 x) (proj1 y) | |||
| proj2 (VNe s xs) = VNe s (PProj2:xs) | |||
| proj2 (VOfSub (VSigma _ d r) phi u0 x) = | |||
| VOfSub (r (proj1 x)) phi (proj2 u0) (proj2 x) | |||
| proj2 x = error $ "can't proj2 " ++ show x | |||
| pathp :: Env -> Value -> Value -> Value -> Value -> Value -> Value | |||
| pathp env p x y f@(VLine _a _x _y e) i = | |||
| case reduceCube env i of | |||
| Just P.Bot -> VEqGlued (e i) x | |||
| Just P.Top -> VEqGlued (e i) y | |||
| _ -> e i | |||
| pathp env p x y (VEqGlued e e') i = VEqGlued (pathp env p x y e i) (pathp env p x y e' i) | |||
| pathp env p x y (VNe hd sp) i = | |||
| case reduceCube env i of | |||
| Just P.Bot -> VEqGlued (VNe hd (PPathP p x y i:sp)) x | |||
| Just P.Top -> VEqGlued (VNe hd (PPathP p x y i:sp)) y | |||
| _ -> VNe hd (PPathP p x y i:sp) | |||
| pathp env p x y (VOfSub _ _ _ v) i = pathp env p x y v i | |||
| comp :: Env -> Value -> Formula -> Value -> Value -> Value | |||
| comp env a@(VLam ivar VI fam) phi u a0 = go (fam undefined) phi u a0 where | |||
| i = VVar ivar | |||
| stuck :: Value | |||
| stuck = maybeAddEq $ VComp a (toValue phi) u a0 | |||
| maybeAddEq :: Value -> Value | |||
| maybeAddEq = | |||
| if phi == P.Top | |||
| then flip VEqGlued (u @@ VI1) | |||
| else id | |||
| go :: HasCallStack => Value -> Formula -> Value -> Value -> Value | |||
| go VPi{} phi u a0 = | |||
| let | |||
| dom x = let VPi _ d _ = fam x in d | |||
| rng x = let VPi _ d _ = fam x in d | |||
| ai1 = dom VI0 | |||
| y' i y = fill env i (dom . inot . fam) P.Bot (VSystem emptySystem) y | |||
| ybar i y = y' (inot i) y | |||
| in VLam "x" ai1 \arg -> | |||
| comp env | |||
| (VLam ivar VI (\i -> rng (ybar i arg))) | |||
| phi | |||
| (VLam "i" VI \i -> mapVSystem (u @@ i) (@@ ybar i arg)) | |||
| (a0 @@ ybar VI0 arg) | |||
| go VSigma{} phi u a0 = | |||
| let | |||
| dom x = let VSigma _ d _ = fam x in d | |||
| rng x = let VSigma _ d _ = fam x in d | |||
| a i = fill env i (dom . fam) phi (VLam "j" VI \v -> mapVSystem (u @@ v) proj1) (proj1 a0) | |||
| c1 = comp env (VLam ivar VI (getd . fam)) phi (VLam "i" VI \v -> mapVSystem (u @@ v) proj1) (proj1 a0) | |||
| c2 = comp env (VLam ivar VI (apr (a VI1) . fam)) phi (VLam "i" VI \v -> mapVSystem (u @@ v) proj2) (proj2 a0) | |||
| getd (VSigma _ d _) = d | |||
| apr x (VSigma _ _ r) = r x | |||
| in VPair c1 c2 | |||
| go VPath{} phi p p0 = | |||
| let | |||
| ~(VPath ai1 u1 v1) = fam VI1 | |||
| ~(VPath ai0 u0 v0) = fam VI0 | |||
| getA (VPath a _ _) = a | |||
| u' x = let ~(VPath _ u _) = fam x in u | |||
| v' x = let ~(VPath _ _ v) = fam x in v | |||
| in | |||
| VLine (ai1 @@ VI1) u1 v1 \j -> | |||
| let | |||
| jc = reduceCube' env j | |||
| in comp env (VLam ivar VI (getA . fam)) | |||
| (orFormula [phi, jc, notFormula jc]) | |||
| (VLam "j" VI \v -> | |||
| let | |||
| VSystem (FMap sys) = p @@ v | |||
| sys' = fmap (flip (pathp env ai0 u0 v0) j) sys | |||
| in mkVSystem $ Map.fromList [(phi, mapVSystem (p @@ v) (flip (pathp env ai0 u0 v0) j)) | |||
| , (notFormula jc, u' v), (jc, v' v)]) | |||
| (pathp env (ai0 @@ VI0) u0 v0 p0 j) | |||
| go a P.Top u a0 = u @@ VI1 | |||
| go a phi u a0 = maybeAddEq stuck | |||
| comp env va phi u a0 = | |||
| if phi == P.Top | |||
| then VEqGlued (VComp va phi' u a0) (u @@ VI1) | |||
| else VComp va phi' u a0 | |||
| where | |||
| phi' = toValue phi | |||
| mkVSystem :: Map.Map Formula Value -> Value | |||
| mkVSystem mp | |||
| | Just e <- Map.lookup P.Top mp = e | |||
| | otherwise = VSystem $ FMap $ Map.filterWithKey f mp | |||
| where | |||
| f P.Bot _ = False | |||
| f _ _ = True | |||
| reduceCube' :: Env -> Value -> Formula | |||
| reduceCube' env = fromJust . reduceCube env | |||
| mapVSystem :: Value -> (Value -> Value) -> Value | |||
| mapVSystem (VSystem ss) f = VSystem (mapSystem ss f) | |||
| mapVSystem x f = f x | |||
| evalSystem :: Env -> Map.Map Formula Term -> Value | |||
| evalSystem env face = mk . Map.mapMaybeWithKey go $ face where | |||
| go :: Formula -> Term -> Maybe Value | |||
| go face tm | |||
| | VI0 <- toValue' env face = Nothing | |||
| | otherwise = Just (eval env tm) | |||
| differsFromEnv :: String -> Bool -> Bool | |||
| differsFromEnv x True = | |||
| case Map.lookup x (names env) of | |||
| Just (VI, VI0) -> True | |||
| _ -> False | |||
| differsFromEnv x False = | |||
| case Map.lookup x (names env) of | |||
| Just (VI, VI1) -> True | |||
| _ -> False | |||
| mk x = case Map.toList x of | |||
| [(_, x)] -> x | |||
| _ -> mkVSystem x | |||
| eval :: Env -> Term -> Value | |||
| eval env = \case | |||
| Var v -> | |||
| case Map.lookup v (names env) of | |||
| Just (_, vl) -> vl | |||
| Nothing -> error $ "variable not in scope: " ++ show v | |||
| App f x -> eval env f @@ eval env x | |||
| Lam s d b -> | |||
| let d' = eval env d | |||
| in VLam s d' \a -> eval env{ names = Map.insert s (d', a) (names env) } b | |||
| Let s t b d -> | |||
| let b' = eval env b | |||
| t' = eval env t | |||
| in eval env{ names = Map.insert s (t', b') (names env) } d | |||
| Pi s d r -> | |||
| let d' = eval env d | |||
| in VPi s d' \a -> eval env{ names = Map.insert s (d', a) (names env) } r | |||
| Sigma s d r -> | |||
| let d' = eval env d | |||
| in VSigma s d' \a -> eval env{ names = Map.insert s (d', a) (names env) } r | |||
| Pair a b -> VPair (eval env a) (eval env b) | |||
| Proj1 x -> proj1 (eval env x) | |||
| Proj2 y -> proj2 (eval env y) | |||
| Type -> VType | |||
| I -> VI | |||
| I0 -> VI0 | |||
| I1 -> VI1 | |||
| Path p x y -> VPath (eval env p) (eval env x) (eval env y) | |||
| Partial r a -> VPartial (eval env r) (eval env a) | |||
| PathI p x y s e -> VLine (eval env p) (eval env x) (eval env y) (\ a -> eval env{ names = Map.insert s (VI, a) (names env) } e) | |||
| PathP p x y f i -> pathp env (eval env p) (eval env x) (eval env y) (eval env f) (eval env i) | |||
| Sub p x y -> VSub (eval env p) (eval env x) (eval env y) | |||
| InclSub a phi u a0 -> VOfSub (eval env a) (eval env phi) (eval env u) (eval env a0) | |||
| IAnd x y -> iand (eval env x) (eval env y) | |||
| IOr x y -> ior (eval env x) (eval env y) | |||
| INot x -> inot (eval env x) | |||
| Comp a phi u a0 -> | |||
| case reduceCube env (eval env phi) of | |||
| Just formula -> comp env (eval env a) formula (eval env u) (eval env a0) | |||
| Nothing -> VComp (eval env a) (eval env phi) (eval env u) (eval env a0) | |||
| System fs -> evalSystem env (getSystem fs) | |||
| data UnifyError | |||
| = Mismatch Value Value | |||
| | NotPiType Value | |||
| | NotPartialType Formula Value | |||
| | NotSigmaType Value | |||
| deriving (Show, Typeable, Exception) | |||
| unify :: Env -> Value -> Value -> IO () | |||
| unify env (VEqGlued a b) c = | |||
| unify env a c `catch` \e -> const (unify env b c) (e :: UnifyError) | |||
| unify env c (VEqGlued a b) = | |||
| unify env c a `catch` \e -> const (unify env c b) (e :: UnifyError) | |||
| unify env (VLine a x y f) e = unify env (f (VVar "i")) (pathp env a x y e (VVar "i")) | |||
| unify env e (VLine a x y f) = unify env (f (VVar "i")) (pathp env a x y e (VVar "i")) | |||
| unify env (VPartial r b) (VPartial r' b') = do | |||
| unify env b b' | |||
| case sameCube env r r' of | |||
| Just True -> pure () | |||
| _ -> unify env r r' | |||
| unify env (VPartial r b) x = do | |||
| case sameCube env r VI1 of | |||
| Just True -> pure () | |||
| _ -> unify env r VI1 | |||
| unify env b x | |||
| unify env x (VPartial r b) = do | |||
| case sameCube env r VI1 of | |||
| Just True -> pure () | |||
| _ -> unify env r VI1 | |||
| unify env x b | |||
| unify env (VSub a phi _u0) vl = unify env a vl | |||
| unify env u1 (VOfSub _a phi u0 a) = do | |||
| case sameCube env phi VI1 of | |||
| Just True -> unify env u1 u0 | |||
| _ -> unify env u1 a | |||
| unify env (VOfSub _a phi u0 a) u1 = do | |||
| case sameCube env phi VI1 of | |||
| Just True -> unify env u1 u0 | |||
| _ -> unify env u1 a | |||
| unify env vl1@(VNe x sp) vl2@(VNe y sp') | |||
| | x == y = traverse_ (uncurry unifySp) (zip sp sp') | |||
| | otherwise = throwIO $ Mismatch vl1 vl2 | |||
| where | |||
| unifySp (PApp x) (PApp y) = unify env x y | |||
| unifySp (PPathP _a _x _y i) (PPathP _a' _x' _y' i') = unify env i i' | |||
| unifySp PProj1 PProj1 = pure () | |||
| unifySp PProj2 PProj2 = pure () | |||
| unify env (VLam x _ k) e = unify env (k (VVar x)) (e @@ VVar x) | |||
| unify env e (VLam x _ k) = unify env (e @@ VVar x) (k (VVar x)) | |||
| unify env (VPi x d r) (VPi _ d' r') = do | |||
| unify env d d' | |||
| unify env (r (VVar x)) (r' (VVar x)) | |||
| unify env (VSigma x d r) (VSigma _ d' r') = do | |||
| unify env d d' | |||
| unify env (r (VVar x)) (r' (VVar x)) | |||
| unify env VType VType = pure () | |||
| unify env VI VI = pure () | |||
| unify env (VPair a b) (VPair c d) = unify env a c *> unify env b d | |||
| unify env (VPath a x y) (VPath a' x' y') = unify env a a' *> unify env x x' *> unify env y y' | |||
| unify env (VSystem fs) vl | |||
| | ((_, vl'):_) <- Map.toList (Map.filterWithKey (\f _ -> isTrue (toValue' env f)) (getSystem fs)) | |||
| = unify env vl' vl | |||
| unify env vl (VSystem fs) | |||
| | ((_, vl'):_) <- Map.toList (Map.filterWithKey (\f _ -> isTrue (toValue' env f)) (getSystem fs)) | |||
| = unify env vl' vl | |||
| unify env x y = | |||
| case sameCube env x y of | |||
| Just True -> pure () | |||
| _ -> throwIO $ Mismatch x y | |||
| reduceCube :: Env -> Value -> Maybe Formula | |||
| reduceCube env x = fmap (toDNF . simplify) (toFormula x) where | |||
| simplify :: Formula -> Formula | |||
| simplify (P.Is0 x) = | |||
| case Map.lookup x (names env) of | |||
| Just (VI, VI0) -> P.Top | |||
| Just (VI, VI1) -> P.Bot | |||
| _ -> P.Is0 x | |||
| simplify (P.Is1 x) = | |||
| case Map.lookup x (names env) of | |||
| Just (VI, VI1) -> P.Top | |||
| Just (VI, VI0) -> P.Bot | |||
| _ -> P.Is0 x | |||
| simplify (P.And x y) = P.And (simplify x) (simplify y) | |||
| simplify (P.Or x y) = P.Or (simplify x) (simplify y) | |||
| simplify x = x | |||
| sameCube :: Env -> Value -> Value -> Maybe Bool | |||
| sameCube env x y = | |||
| case (reduceCube env x, reduceCube env y) of | |||
| (Just x, Just y) -> Just (x == y) | |||
| _ -> Nothing | |||
| toFormula :: Value -> Maybe Formula | |||
| toFormula VI0 = Just P.Bot | |||
| toFormula VI1 = Just P.Top | |||
| toFormula (VNe x []) = Just (P.Is1 x) | |||
| toFormula (VINot f) = notFormula <$> toFormula f | |||
| toFormula (VIAnd x y) = do | |||
| s <- toFormula y | |||
| t <- toFormula x | |||
| pure $ andFormula [s, t] | |||
| toFormula (VIOr x y) = do | |||
| s <- toFormula y | |||
| t <- toFormula x | |||
| pure $ orFormula [s, t] | |||
| toFormula _ = Nothing | |||
| faceInEnv :: Env -> Face -> Bool | |||
| faceInEnv e f = Map.isSubmapOf (getFace f) (faceOfEnv (names e)) where | |||
| faceOfEnv = Map.map (\(_, v) -> case v of { VI1 -> True; VEqGlued _ VI1 -> True; _ -> False }) . Map.filter (\(_, v) -> isI v) | |||
| isI VI1 = True | |||
| isI VI0 = True | |||
| isI (VEqGlued _ x) = isI x | |||
| isI _ = False | |||
| isPiType :: Value -> IO (String, Value, Value -> Value) | |||
| isPiType (VPi x d r) = pure (x, d, r) | |||
| isPiType x = throwIO $ NotPiType x | |||
| isSigmaType :: Value -> IO (String, Value, Value -> Value) | |||
| isSigmaType (VSigma x d r) = pure (x, d, r) | |||
| isSigmaType x = throwIO $ NotSigmaType x | |||
| isPiOrPathType :: Value -> IO (Either (String, Value, Value -> Value) (Value, Value, Value)) | |||
| isPiOrPathType (VPi x d r) = pure (Left (x, d, r)) | |||
| isPiOrPathType (VPath x d r) = pure (Right (x, d, r)) | |||
| isPiOrPathType x = throwIO $ NotPiType x | |||
| isPartialType :: Formula -> Value -> IO (Formula, Value) | |||
| isPartialType f p@(VPartial x y) = | |||
| case toFormula x of | |||
| Just x -> pure (x, y) | |||
| Nothing -> throwIO $ NotPartialType f p | |||
| isPartialType f x = throwIO $ NotPartialType f x | |||
| getVar :: IO Value | |||
| getVar = | |||
| do | |||
| n <- atomicModifyIORef ref \x -> (x + 1, x) | |||
| pure (VVar (show n)) | |||
| where | |||
| ref :: IORef Int | |||
| ref = unsafePerformIO (newIORef 0) | |||
| {-# NOINLINE ref #-} | |||
| fill :: Env | |||
| -> Value | |||
| -> (Value -> Value) -- (Γ i : I, A : Type) | |||
| -> Formula -- (phi : I) | |||
| -> Value -- (u : (i : I) -> Partial phi (A i)) | |||
| -> Value -- (Sub (A i0) phi (u i0)) | |||
| -> Value -- -> A i | |||
| fill env i a phi u a0 = | |||
| comp env | |||
| (VLam "j" VI \j -> a (i `iand` j)) | |||
| (phi `P.Or` ifc) | |||
| (VLam "j" VI \j -> | |||
| mkVSystem (Map.fromList [ (phi, uiand j) | |||
| , (notFormula ifc, a0) ])) | |||
| a0 | |||
| where | |||
| uiand j = u @@ (i `iand` j) | |||
| ifc = fromJust (reduceCube env i) | |||
| toValue :: Formula -> Value | |||
| toValue P.Top = VI1 | |||
| toValue P.Bot = VI0 | |||
| toValue (P.And x y) = toValue x `iand` toValue y | |||
| toValue (P.Or x y) = toValue x `ior` toValue y | |||
| toValue (P.Is0 x) = inot (VVar x) | |||
| toValue (P.Is1 x) = VVar x | |||
| toValue' :: Env -> Formula -> Value | |||
| toValue' env P.Top = VI1 | |||
| toValue' env P.Bot = VI0 | |||
| toValue' env (P.And x y) = toValue x `iand` toValue y | |||
| toValue' env (P.Or x y) = toValue x `ior` toValue y | |||
| toValue' env (P.Is0 x) = | |||
| case Map.lookup x (names env) of | |||
| Just (VI, VI0) -> VI1 | |||
| Just (VI, VI1) -> VI0 | |||
| Just (VI, x) -> inot x | |||
| _ -> error $ "type error in toValue'" | |||
| toValue' env (P.Is1 x) = | |||
| case Map.lookup x (names env) of | |||
| Just (VI, x) -> x | |||
| _ -> error $ "type error in toValue'" | |||
| isTrue :: Value -> Bool | |||
| isTrue VI1 = True | |||
| isTrue _ = False | |||
| @ -0,0 +1,134 @@ | |||
| {-# LANGUAGE LambdaCase #-} | |||
| module Main where | |||
| import Presyntax.Parser | |||
| import Elab | |||
| import Control.Monad.Catch | |||
| import System.Exit | |||
| import Syntax | |||
| import System.Console.Haskeline (runInputT, defaultSettings, getInputLine) | |||
| import Control.Monad.IO.Class | |||
| import Presyntax | |||
| import qualified Data.Map.Strict as Map | |||
| import Eval (eval, UnifyError (..)) | |||
| import Systems (formulaOfFace, Face) | |||
| import Data.List | |||
| 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 | |||
| code <- readFile "test.itt" | |||
| case parseString body code of | |||
| Left e -> print e | |||
| Right x -> do | |||
| (tm, _) <- infer (Env mempty ) x `catch` \e -> do | |||
| putStrLn $ showTypeError (Just (lines code)) e | |||
| exitFailure | |||
| print 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 $ 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 $ check env t VType | |||
| let t' = eval env t | |||
| b <- liftIO $ 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)") | |||
| @ -0,0 +1,71 @@ | |||
| {-# LANGUAGE LambdaCase #-} | |||
| module Presyntax where | |||
| data Exp | |||
| = Var String | |||
| | App Exp Exp | |||
| | Lam String Exp | |||
| | Let String Exp Exp Exp | |||
| | Sigma String Exp Exp | |||
| | Pair Exp Exp | |||
| | Proj1 Exp | |||
| | Proj2 Exp | |||
| | Pi String Exp Exp | |||
| | Type | |||
| | I | |||
| | I0 | I1 | |||
| | IAnd Exp Exp | |||
| | IOr Exp Exp | |||
| | INot Exp | |||
| | Path | |||
| | Cut Exp Exp | |||
| | Span (Int, Int) (Int, Int) Exp | |||
| -- Formulas, partial elements, and the type of formulas | |||
| | Partial [(Formula, Exp)] | |||
| | PartialT | |||
| -- Compositions | |||
| | Comp | |||
| -- Cubical subtypes | |||
| | SubT | |||
| deriving (Eq, Show, Ord) | |||
| data Formula | |||
| = Is0 String | |||
| | Is1 String | |||
| | And Formula Formula | |||
| | Or Formula Formula | |||
| | Top | Bot | |||
| deriving (Eq, Ord) | |||
| instance Show Formula where | |||
| showsPrec p = | |||
| \case | |||
| Is1 i -> showString i | |||
| Is0 i -> showString ('~':i) | |||
| And x y -> showParen (p > and_prec) $ | |||
| showsPrec or_prec x | |||
| . showString " && " | |||
| . showsPrec or_prec y | |||
| Or x y -> showParen (p > or_prec) $ | |||
| showsPrec or_prec x | |||
| . showString " || " | |||
| . showsPrec or_prec y | |||
| Top -> showString "i1" | |||
| Bot -> showString "i0" | |||
| where | |||
| and_prec = 2 | |||
| or_prec = 1 | |||
| data Statement | |||
| = Assume [(String, Exp)] | |||
| | Declare String Exp Exp | |||
| | Eval Exp | |||
| @ -0,0 +1,192 @@ | |||
| {-# LANGUAGE BangPatterns #-} | |||
| module Presyntax.Lexer where | |||
| import Data.Text (Text) | |||
| import Data.Char | |||
| import qualified Data.Text as T | |||
| {- HLINT ignore -} | |||
| data TokenClass | |||
| = Tok_var Text | |||
| | Tok_lambda | |||
| | Tok_type | |||
| | Tok_path | |||
| | Tok_phi | |||
| | Tok_sub | |||
| | Tok_comp | |||
| | Tok_tr | |||
| | Tok_I | |||
| | Tok_I0 | |||
| | Tok_I1 | |||
| | Tok_oparen | |||
| | Tok_cparen | |||
| | Tok_osquare | |||
| | Tok_csquare | |||
| | Tok_colon | |||
| | Tok_arrow | |||
| | Tok_let | |||
| | Tok_equal | |||
| | Tok_in | |||
| | Tok_and | |||
| | Tok_not | |||
| | Tok_or | |||
| | Tok_fand | |||
| | Tok_for | |||
| | Tok_assume | |||
| | Tok_p1 | |||
| | Tok_p2 | |||
| | Tok_comma | |||
| | Tok_times | |||
| deriving (Eq, Show, Ord) | |||
| data Token | |||
| = Token { tokLine :: {-# UNPACK #-} !Int | |||
| , tokCol :: {-# UNPACK #-} !Int | |||
| , tokSOff :: {-# UNPACK #-} !Int | |||
| , tokOff :: {-# UNPACK #-} !Int | |||
| , tokClass :: !TokenClass | |||
| } | |||
| deriving (Eq, Show, Ord) | |||
| data LexError | |||
| = LexError { leChar :: {-# UNPACK #-} !Char | |||
| , leLine :: {-# UNPACK #-} !Int | |||
| , leCol :: {-# UNPACK #-} !Int | |||
| } | |||
| | EOFInComment { leLine :: {-# UNPACK #-} !Int | |||
| , leCol :: {-# UNPACK #-} !Int | |||
| } | |||
| deriving (Eq, Show, Ord) | |||
| lexString :: String -> Either LexError [Token] | |||
| lexString = go 0 0 0 where | |||
| go :: Int -> Int -> Int -> String -> Either LexError [Token] | |||
| go !off !line !_ ('\n':xs) = | |||
| go (off + 1) (line + 1) 0 xs | |||
| go !off !line !col (' ':xs) = | |||
| go (off + 1) line (col + 1) xs | |||
| go !off !line !_ ('-':'-':xs) = | |||
| let (a, b) = span (/= '\n') xs | |||
| in go (off + length a) line 0 b | |||
| go !off !line !col ('{':'-':xs) = skipComment off line col 1 xs | |||
| go !off !line !col ('~':cs) = | |||
| Token line col off (off + 1) Tok_not `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('(':cs) = | |||
| Token line col off (off + 1) Tok_oparen `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col (')':cs) = | |||
| Token line col off (off + 1) Tok_cparen `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('[':cs) = | |||
| Token line col off (off + 1) Tok_osquare `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col (']':cs) = | |||
| Token line col off (off + 1) Tok_csquare `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col (':':cs) = | |||
| Token line col off (off + 1) Tok_colon `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col (',':cs) = | |||
| Token line col off (off + 1) Tok_comma `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('=':cs) = | |||
| Token line col off (off + 1) Tok_equal `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('\\':'/':cs) = | |||
| Token line col off (off + 2) Tok_for `yield` go (off + 2) line (col + 2) cs | |||
| go !off !line !col ('\\':cs) = | |||
| Token line col off (off + 1) Tok_lambda `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('*':cs) = | |||
| Token line col off (off + 1) Tok_times `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('λ':cs) = | |||
| Token line col off (off + 1) Tok_lambda `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('→':cs) = | |||
| Token line col off (off + 1) Tok_lambda `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('-':'>':cs) = | |||
| Token line col off (off + 2) Tok_arrow `yield` go (off + 2) line (col + 2) cs | |||
| go !off !line !col ('&':'&':cs) = | |||
| Token line col off (off + 2) Tok_and `yield` go (off + 2) line (col + 2) cs | |||
| go !off !line !col ('&':cs) = | |||
| Token line col off (off + 1) Tok_fand `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('/':'\\':cs) = | |||
| Token line col off (off + 1) Tok_fand `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('|':'|':cs) = | |||
| Token line col off (off + 2) Tok_or `yield` go (off + 2) line (col + 2) cs | |||
| go !off !line !col ('|':cs) = | |||
| Token line col off (off + 1) Tok_for `yield` go (off + 1) line (col + 1) cs | |||
| go !off !line !col ('.':'1':cs) = | |||
| Token line col off (off + 2) Tok_p1 `yield` go (off + 2) line (col + 2) cs | |||
| go !off !line !col ('.':'2':cs) = | |||
| Token line col off (off + 2) Tok_p2 `yield` go (off + 2) line (col + 2) cs | |||
| go !off !line !col (c:cs) | |||
| | isAlpha c = goIdent off off line col (T.singleton c) cs | |||
| go !_ !line !col (c:_) = Left (LexError c line col) | |||
| go _ _ _ [] = pure [] | |||
| goIdent !soff !off !line !col !acc [] = | |||
| pure [Token line col soff off (finishIdent acc)] | |||
| goIdent !soff !off !line !col !acc (c:cs) | |||
| | isAlphaNum c || c == '\'' | |||
| = goIdent soff (off + 1) line (col + 1) (T.snoc acc c) cs | |||
| | otherwise | |||
| = Token line col soff off (finishIdent acc) `yield` go (off + 1) line (col + 1) (c:cs) | |||
| skipComment off line col level ('-':'}':cs) | |||
| | level == 1 = go (off + 2) line (col + 2) cs | |||
| | otherwise = skipComment (off + 2) line (col + 2) (level - 1) cs | |||
| skipComment off line col level ('{':'-':cs) = | |||
| skipComment (off + 2) line (col + 2) (level + 1) cs | |||
| skipComment off line col level ('\n':cs) = | |||
| skipComment (off + 1) (line + 1) 0 level cs | |||
| skipComment off line col level (c:cs) = | |||
| skipComment (off + 1) line (col + 1) level cs | |||
| skipComment _ line col _ [] = Left (EOFInComment line col) | |||
| yield c = fmap (c:) | |||
| finishIdent c | |||
| | T.pack "Type" == c = Tok_type | |||
| | T.pack "Path" == c = Tok_path | |||
| | T.pack "Partial" == c = Tok_phi | |||
| | T.pack "Sub" == c = Tok_sub | |||
| | T.pack "comp" == c = Tok_comp | |||
| | T.pack "tr" == c = Tok_tr | |||
| | T.pack "I" == c = Tok_I | |||
| | T.pack "i0" == c = Tok_I0 | |||
| | T.pack "i1" == c = Tok_I1 | |||
| | T.pack "let" == c = Tok_let | |||
| | T.pack "in" == c = Tok_in | |||
| | T.pack "assume" == c = Tok_assume | |||
| | otherwise = Tok_var c | |||
| @ -0,0 +1,284 @@ | |||
| {-# LANGUAGE TupleSections #-} | |||
| {-# LANGUAGE BlockArguments #-} | |||
| {-# LANGUAGE LambdaCase #-} | |||
| {-# LANGUAGE DerivingVia #-} | |||
| module Presyntax.Parser where | |||
| import Control.Applicative | |||
| import Control.Monad.State | |||
| import qualified Data.Text as T | |||
| import Data.Text (Text) | |||
| import Presyntax.Lexer | |||
| import Presyntax | |||
| data ParseError | |||
| = UnexpectedEof Int Int | |||
| | Unexpected Token | |||
| | Empty | |||
| | AltError ParseError ParseError | |||
| deriving (Show) | |||
| data ParseState | |||
| = ParseState { ptTs :: [Token] | |||
| , ptLine :: !Int | |||
| , ptCol :: !Int | |||
| } | |||
| newtype Parser a = | |||
| Parser { runParser :: ParseState -> Either ParseError (a, ParseState) } | |||
| deriving | |||
| ( Functor | |||
| , Applicative | |||
| , Monad | |||
| , MonadState ParseState | |||
| ) | |||
| via (StateT ParseState (Either ParseError)) | |||
| eof :: Parser () | |||
| eof = Parser $ \state -> | |||
| case ptTs state of | |||
| [] -> Right ((), state) | |||
| (x:_) -> Left (Unexpected x) | |||
| parseString :: Parser a -> String -> Either (Either LexError ParseError) a | |||
| parseString (Parser k) s = | |||
| case lexString s of | |||
| Left e -> Left (Left e) | |||
| Right xs -> | |||
| case k (ParseState xs 0 0) of | |||
| Left e -> Left (pure e) | |||
| Right (x, _) -> Right x | |||
| selectToken :: (Token -> Maybe a) -> Parser a | |||
| selectToken k = Parser \case | |||
| ParseState [] l c -> Left (UnexpectedEof l c) | |||
| ParseState (x:xs) _ _ -> | |||
| case k x of | |||
| Just p -> pure (p, ParseState xs (tokLine x) (tokCol x)) | |||
| Nothing -> Left (Unexpected x) | |||
| expect :: TokenClass -> Parser () | |||
| expect t = selectToken (\x -> if tokClass x == t then Just () else Nothing) | |||
| var :: Parser Text | |||
| var = selectToken \case | |||
| Token _ _ _ _ (Tok_var v) -> pure v | |||
| _ -> Nothing | |||
| optionally :: Parser a -> Parser (Maybe a) | |||
| optionally p = fmap Just p <|> pure Nothing | |||
| parens :: Parser a -> Parser a | |||
| parens k = do | |||
| expect Tok_oparen | |||
| x <- k | |||
| expect Tok_cparen | |||
| pure x | |||
| square :: Parser a -> Parser a | |||
| square k = do | |||
| expect Tok_osquare | |||
| x <- k | |||
| expect Tok_csquare | |||
| pure x | |||
| instance Alternative Parser where | |||
| empty = Parser \_ -> Left Empty | |||
| Parser kx <|> Parser ky = Parser \x -> | |||
| case kx x of | |||
| Right x -> Right x | |||
| Left e -> | |||
| case ky x of | |||
| Left _ -> Left e | |||
| Right y -> Right y | |||
| attachPos :: Parser Exp -> Parser Exp | |||
| attachPos k = do | |||
| start <- gets (\(ParseState ~(x:_) _ _) -> (tokLine x, tokCol x - (tokOff x - tokSOff x))) | |||
| x <- k | |||
| end <- gets (\(ParseState _ l c) -> (l, c)) | |||
| pure (Span start end x) | |||
| body :: Parser Exp | |||
| body = attachPos letExpr <|> attachPos lamExpr <|> attachPos exprPi where | |||
| lamExpr = do | |||
| expect Tok_lambda | |||
| vs <- some arg | |||
| expect Tok_arrow | |||
| e <- body | |||
| pure (foldr Lam e vs) | |||
| letExpr = do | |||
| expect Tok_let | |||
| v <- T.unpack <$> var | |||
| expect Tok_colon | |||
| t <- body | |||
| expect Tok_equal | |||
| b <- body | |||
| expect Tok_in | |||
| Let v t b <$> body | |||
| arg = T.unpack <$> var | |||
| exprPi :: Parser Exp | |||
| exprPi = attachPos $ | |||
| do | |||
| bs <- optionally binder | |||
| case bs of | |||
| Just k -> foldl (.) id k <$> attachPos exprPi | |||
| Nothing -> attachPos exprArr | |||
| where | |||
| binder = (some (parens bind) <* expect Tok_arrow) | |||
| <|> (fmap pure (parens sigma) <* expect Tok_times) | |||
| bind = do | |||
| names <- some (T.unpack <$> var) | |||
| expect Tok_colon | |||
| t <- exprPi | |||
| pure (foldr (\n k -> Pi n t . k) id names) | |||
| sigma = do | |||
| names <- some (T.unpack <$> var) | |||
| expect Tok_colon | |||
| t <- exprPi | |||
| pure (foldr (\n k -> Sigma n t . k) id names) | |||
| exprArr :: Parser Exp | |||
| exprArr = attachPos $ do | |||
| t <- attachPos exprConj | |||
| c <- optionally (fmap (const True) (expect Tok_arrow) <|> fmap (const False) (expect Tok_times)) | |||
| case c of | |||
| Just True -> Pi "_" t <$> exprPi | |||
| Just False -> Sigma "_" t <$> exprPi | |||
| Nothing -> pure t | |||
| exprApp :: Parser Exp | |||
| exprApp = attachPos $ | |||
| do | |||
| head <- atom | |||
| spine <- many spineEntry | |||
| pure (foldl app head spine) | |||
| where | |||
| spineEntry = atom | |||
| app f s = App f s | |||
| exprDisj :: Parser Exp | |||
| exprDisj = attachPos $ | |||
| do | |||
| first <- exprApp | |||
| rest <- many disjunct | |||
| pure (foldl IOr first rest) | |||
| where | |||
| disjunct = expect Tok_or *> exprApp | |||
| exprConj :: Parser Exp | |||
| exprConj = attachPos $ | |||
| do | |||
| first <- exprDisj | |||
| rest <- many conjunct | |||
| pure (foldl IAnd first rest) | |||
| where | |||
| conjunct = expect Tok_and *> exprDisj | |||
| atom0 :: Parser Exp | |||
| atom0 = attachPos $ | |||
| fmap (Var . T.unpack) var | |||
| <|> fmap (const Type) (expect Tok_type) | |||
| <|> fmap (const I) (expect Tok_I) | |||
| <|> fmap (const I0) (expect Tok_I0) | |||
| <|> fmap (const I1) (expect Tok_I1) | |||
| <|> fmap (const Path) (expect Tok_path) | |||
| <|> fmap (const SubT) (expect Tok_sub) | |||
| <|> fmap (const PartialT) (expect Tok_phi) | |||
| <|> fmap (const Comp) (expect Tok_comp) | |||
| <|> fmap INot (expect Tok_not *> atom) | |||
| <|> parens pair | |||
| <|> square (Partial <$> (system <|> pure [])) | |||
| atom :: Parser Exp | |||
| atom = attachPos $ | |||
| do | |||
| e <- atom0 | |||
| c <- many (selectToken (projection . tokClass)) | |||
| pure $ case c of | |||
| [] -> e | |||
| sls -> foldl (flip ($)) e sls | |||
| where | |||
| projection Tok_p1 = pure Proj1 | |||
| projection Tok_p2 = pure Proj2 | |||
| projection _ = Nothing | |||
| system :: Parser [(Formula, Exp)] | |||
| system = | |||
| do | |||
| t <- comp | |||
| x <- optionally (expect Tok_comma) | |||
| case x of | |||
| Just () -> (t:) <$> system | |||
| Nothing -> pure [t] | |||
| where | |||
| comp = do | |||
| t <- formula | |||
| expect Tok_arrow | |||
| (t,) <$> body | |||
| pair :: Parser Exp | |||
| pair = do | |||
| t <- body | |||
| x <- optionally (expect Tok_comma) | |||
| case x of | |||
| Just () -> Pair t <$> pair | |||
| Nothing -> pure t | |||
| statement :: Parser Statement | |||
| statement = (assume <|> declare <|> (Eval <$> body)) <* eof where | |||
| assume = do | |||
| expect Tok_assume | |||
| Assume <$> vars | |||
| declare = do | |||
| expect Tok_let | |||
| x <- T.unpack <$> var | |||
| expect Tok_colon | |||
| ty <- body | |||
| expect Tok_equal | |||
| Declare x ty <$> body | |||
| bind = do | |||
| var <- some (T.unpack <$> var) | |||
| expect Tok_colon | |||
| body <- body | |||
| pure $ map ((, body)) var | |||
| vars = do | |||
| var <- bind | |||
| t <- optionally (expect Tok_comma) | |||
| case t of | |||
| Nothing -> pure var | |||
| Just x -> (var ++) <$> vars | |||
| formula :: Parser Formula | |||
| formula = conjunction where | |||
| conjunction, disjunction, atom :: Parser Formula | |||
| conjunction = do | |||
| d <- disjunction | |||
| t <- optionally (expect Tok_and) | |||
| case t of | |||
| Nothing -> pure d | |||
| Just x -> And d <$> conjunction | |||
| disjunction = do | |||
| d <- atom | |||
| t <- optionally (expect Tok_or) | |||
| case t of | |||
| Nothing -> pure d | |||
| Just x -> Or d <$> disjunction | |||
| atom = (Is1 . T.unpack) <$> var | |||
| <|> (Is0 . T.unpack) <$> (expect Tok_not *> var) | |||
| <|> Top <$ expect Tok_I1 | |||
| <|> Bot <$ expect Tok_I0 | |||
| @ -0,0 +1,250 @@ | |||
| {-# LANGUAGE LambdaCase #-} | |||
| {-# LANGUAGE PatternSynonyms #-} | |||
| module Syntax where | |||
| import Data.Set (Set) | |||
| import qualified Data.Set as Set | |||
| import Data.Map.Strict (Map) | |||
| import Systems | |||
| import qualified Data.Map.Strict as Map | |||
| import Text.Show (showListWith) | |||
| import Presyntax (Formula) | |||
| type Space = Term | |||
| data Term | |||
| = Var String | |||
| | App Term Term | |||
| | Lam String Term Term | |||
| | Let String Term Term Term | |||
| | Pi String Term Term | |||
| | Type | |||
| | I | |||
| | I0 | I1 | |||
| | IAnd Term Term | |||
| | IOr Term Term | |||
| | INot Term | |||
| | Path Space Term Term | |||
| | PathI Space Term Term String Term | |||
| | PathP Space Term Term Term Term | |||
| | Sigma String Term Term | |||
| | Pair Term Term | |||
| | Proj1 Term | |||
| | Proj2 Term | |||
| | System (System Term) | |||
| | Partial Term Term | |||
| | Comp Term Term Term Term | |||
| | Sub Term Term Term | |||
| | InclSub Term Term Term Term | |||
| deriving (Eq, Ord) | |||
| instance Show Term where | |||
| showsPrec p = | |||
| \case | |||
| Var s -> showString s | |||
| System fs -> showListWith showPE (Map.toList (getSystem fs)) | |||
| -- ew | |||
| App (App (App (Lam _ _ (Lam _ _ (Lam _ _ Path{}))) a) x) y -> showsPrec p (Path a x y) | |||
| App (App (App (Lam _ _ (Lam _ _ (Lam _ _ Sub{}))) a) x) y -> showsPrec p (Sub a x y) | |||
| App (App (Lam _ _ (Lam _ _ Partial{})) phi) r -> showsPrec p (Partial phi r) | |||
| App (App (App (App (Lam _ _ (Lam _ _ (Lam _ _ (Lam _ _ Comp{})))) a) phi) u) a0 -> | |||
| showsPrec p (Comp a phi u a0) | |||
| App f x -> showParen (p >= app_prec) $ | |||
| showsPrec fun_prec f | |||
| . showChar ' ' | |||
| . showsPrec app_prec x | |||
| Lam s t b -> | |||
| let | |||
| getLams (Lam s _ b) = | |||
| let (as, b') = getLams b | |||
| in (s:as, b') | |||
| getLams (PathI _a _x _y s b) = | |||
| let (as, b') = getLams b | |||
| in (("(" ++ s ++ " : I)"):as, b') | |||
| getLams t = ([], t) | |||
| (args, bd) = getLams (Lam s t b) | |||
| in showParen (p >= fun_prec) $ | |||
| showString ("λ " ++ unwords args ++ " -> ") | |||
| . shows bd | |||
| Let s t d b -> showParen (p > fun_prec) $ | |||
| showString "let\n " | |||
| . showString s | |||
| . showString " : " | |||
| . shows t | |||
| . showString " = " | |||
| . shows d | |||
| . showString " in " | |||
| . shows b | |||
| Pi "_" d r -> | |||
| showParen (p >= domain_prec) $ | |||
| showsPrec domain_prec d | |||
| . showString " -> " | |||
| . shows r | |||
| Pi v d r -> showParen (p >= domain_prec) $ | |||
| let | |||
| showBinder (Pi "_" d r) = | |||
| showsPrec domain_prec d | |||
| . showString " -> " | |||
| . shows r | |||
| showBinder (Pi n d r) = | |||
| let | |||
| arr = case r of | |||
| Pi n _ _ | n /= "_" -> " " | |||
| _ -> " -> " | |||
| in | |||
| showParen True (showString n . showString " : " . shows d) | |||
| . showString arr | |||
| . showBinder r | |||
| showBinder t = shows t | |||
| in showBinder (Pi v d r) | |||
| Type -> showString "Type" | |||
| I -> showChar 'I' | |||
| I0 -> showString "i0" | |||
| I1 -> showString "i1" | |||
| IAnd i j -> showParen (p >= and_prec) $ | |||
| showsPrec or_prec i | |||
| . showString " && " | |||
| . showsPrec or_prec j | |||
| IOr i j -> showParen (p >= or_prec) $ | |||
| showsPrec app_prec i | |||
| . showString " || " | |||
| . showsPrec app_prec j | |||
| INot s -> showChar '~' . showsPrec p s | |||
| Path a x y -> showsPrec p (App (App (App (Var "Path") a) x) y) | |||
| Sub a x y -> showsPrec p (App (App (App (Var "Sub") a) x) y) | |||
| Partial r a -> showsPrec p (App (App (Var "Partial") r) a) | |||
| Comp a phi u a0 -> showsPrec p (foldl App (Var "comp") [a, phi, u, a0]) | |||
| InclSub _a _phi _u0 a0 -> showsPrec p a0 | |||
| PathI a x y s b -> showParen (p >= fun_prec) $ | |||
| showString ("λ " ++ s ++ " -> ") | |||
| . shows b | |||
| PathP _a _x _y f i -> showsPrec p (App f i) | |||
| Pair a b -> showParen True $ | |||
| shows a | |||
| . showString ", " | |||
| . shows b | |||
| Proj1 b -> showsPrec p b . showString ".1" | |||
| Proj2 b -> showsPrec p b . showString ".1" | |||
| Sigma v d r -> | |||
| showParen (p >= app_prec) $ | |||
| showParen True (showString v . showString " : " . shows d) | |||
| . showString " × " | |||
| . shows r | |||
| where | |||
| app_prec = 6 | |||
| domain_prec = 5 | |||
| and_prec = 4 | |||
| or_prec = 3 | |||
| fun_prec = 1 | |||
| showPE :: (Formula, Term) -> String -> String | |||
| showPE (f, t) = shows f . showString " -> " . shows t | |||
| data Value | |||
| = VNe String [Proj] | |||
| | VLam String Value (Value -> Value) | |||
| | VPi String Value (Value -> Value) | |||
| | VType | |||
| | VI | VI0 | VI1 | |||
| | VEqGlued Value Value -- e which is def. eq. to e' | |||
| | VPair Value Value | |||
| | VSigma String Value (Value -> Value) | |||
| | VLine Value Value Value (Value -> Value) | |||
| -- (λ i → ...) : Path A x y | |||
| -- order: A x y k | |||
| | VSystem (System Value) | |||
| | VOfSub Value Value Value Value | |||
| | VIAnd Value Value | |||
| | VIOr Value Value | |||
| | VINot Value | |||
| | VPath Value Value Value | |||
| | VSub Value Value Value | |||
| | VPartial Value Value | |||
| | VComp Value Value Value Value | |||
| data Proj | |||
| = PApp Value | |||
| | PPathP Value Value Value Value | |||
| -- a x y i | |||
| | PProj1 | |||
| | PProj2 | |||
| pattern VVar :: String -> Value | |||
| pattern VVar x = VNe x [] | |||
| quote :: Value -> Term | |||
| quote = go mempty where | |||
| go :: Set String -> Value -> Term | |||
| go scope (VNe hd spine) = foldl (goSpine scope) (Var hd) (reverse spine) | |||
| go scope (VLam s a k) = | |||
| let n = rename s scope | |||
| in Lam n (go scope a) (go (Set.insert n scope) (k (VVar n))) | |||
| go scope (VPi s d r) = | |||
| let n = rename s scope | |||
| in Pi n (go scope d) (go (Set.insert n scope) (r (VVar n))) | |||
| go scope (VSigma s d r) = | |||
| let n = rename s scope | |||
| in Sigma n (go scope d) (go (Set.insert n scope) (r (VVar n))) | |||
| go scope VType = Type | |||
| go scope VI0 = I0 | |||
| go scope VI1 = I1 | |||
| go scope VI = I | |||
| go scope (VIAnd x y) = IAnd (go scope x) (go scope y) | |||
| go scope (VIOr x y) = IOr (go scope x) (go scope y) | |||
| go scope (VINot x) = INot (go scope x) | |||
| go scope (VPath a x y) = Path (go scope a) (go scope x) (go scope y) | |||
| go scope (VSub a x y) = Sub (go scope a) (go scope x) (go scope y) | |||
| go scope (VPartial r a) = Partial (go scope r) (go scope a) | |||
| go scope (VComp a b c d) = Comp (go scope a) (go scope b) (go scope c) (go scope d) | |||
| go scope (VEqGlued e _) = go scope e | |||
| go scope (VPair a b) = Pair (go scope a) (go scope b) | |||
| go scope (VLine a x y k) = | |||
| let n = rename "i" scope | |||
| in PathI (go scope a) (go scope x) (go scope y) n (go (Set.insert n scope) (k (VVar n))) | |||
| go scope (VSystem (FMap fs)) = System (FMap (fmap (go scope) fs)) | |||
| go scope (VOfSub _ _ _ x) = go scope x | |||
| goSpine :: Set String -> Term -> Proj -> Term | |||
| goSpine scope t (PApp x) = App t (go scope x) | |||
| goSpine scope t (PPathP a x y i) = PathP (go scope a) (go scope x) (go scope y) t (go scope i) | |||
| goSpine scope t PProj1 = Proj1 t | |||
| goSpine scope t PProj2 = Proj2 t | |||
| rename :: String -> Set String -> String | |||
| rename x s | |||
| | x == "_" = x | |||
| | x `Set.member` s = rename (x ++ "'") s | |||
| | otherwise = x | |||
| instance Show Value where | |||
| showsPrec p = showsPrec p . quote | |||
| data Env = | |||
| Env { names :: Map String (Value, Value) | |||
| } | |||
| deriving (Show) | |||
| @ -0,0 +1,96 @@ | |||
| module Systems where | |||
| import Data.Map.Strict (Map) | |||
| import Presyntax | |||
| import qualified Data.Map.Strict as Map | |||
| import Data.Set (Set) | |||
| import qualified Data.Set as Set | |||
| import Data.List | |||
| newtype Face = Face { getFace :: Map String Bool } | |||
| deriving (Eq, Show, Ord) | |||
| evalFormula :: Formula -> Face -> Bool | |||
| evalFormula (Is0 x) f = | |||
| case Map.lookup x (getFace f) of | |||
| Just x -> not x | |||
| Nothing -> error $ "dimension not bound in formula: " ++ show x | |||
| evalFormula (Is1 x) f = | |||
| case Map.lookup x (getFace f) of | |||
| Just x -> x | |||
| Nothing -> error $ "dimension not bound in formula: " ++ show x | |||
| evalFormula (And a b) f = evalFormula a f && evalFormula b f | |||
| evalFormula (Or a b) f = evalFormula a f || evalFormula b f | |||
| evalFormula Top _ = True | |||
| evalFormula Bot _ = False | |||
| freeVarsFormula :: Formula -> Set String | |||
| freeVarsFormula (Is0 x) = Set.singleton x | |||
| freeVarsFormula (Is1 x) = Set.singleton x | |||
| freeVarsFormula (And a b) = Set.union (freeVarsFormula a) (freeVarsFormula b) | |||
| freeVarsFormula (Or a b) = Set.union (freeVarsFormula a) (freeVarsFormula b) | |||
| freeVarsFormula Top = mempty | |||
| freeVarsFormula Bot = mempty | |||
| faces :: Formula -> ([Face], [Face]) | |||
| faces formula = partition (evalFormula formula) allPossible where | |||
| truths [] = [mempty] | |||
| truths (x:xs) = uncurry Map.insert <$> [(x, True), (x, False)] <*> truths xs | |||
| allPossible = Face <$> truths (Set.toList (freeVarsFormula formula)) | |||
| impossible, possible, tautological :: Formula -> Bool | |||
| impossible = null . fst . faces | |||
| possible = not . null . fst . faces | |||
| tautological = not . null . snd . faces | |||
| toDNF :: Formula -> Formula | |||
| toDNF = orFormula . map formulaOfFace . fst . faces | |||
| formulaOfFace :: Face -> Formula | |||
| formulaOfFace = andFormula . map (\(x, i) -> if i then Is1 x else Is0 x) . Map.toDescList . getFace | |||
| andFormula :: [Formula] -> Formula | |||
| andFormula = foldr and Top where | |||
| and x y = | |||
| case x of | |||
| Top -> case y of | |||
| Bot -> Bot | |||
| _ -> y | |||
| Bot -> Bot | |||
| _ -> case y of | |||
| Top -> x | |||
| _ -> And x y | |||
| orFormula :: [Formula] -> Formula | |||
| orFormula [] = Bot | |||
| orFormula (x:xs) = or x (orFormula xs) where | |||
| or x y = | |||
| case x of | |||
| Top -> Top | |||
| Bot -> case y of | |||
| Top -> Top | |||
| _ -> y | |||
| _ -> case y of | |||
| Bot -> x | |||
| _ -> Or x y | |||
| notFormula :: Formula -> Formula | |||
| notFormula Top = Bot | |||
| notFormula Bot = Top | |||
| notFormula (Is0 x) = Is1 x | |||
| notFormula (Is1 x) = Is0 x | |||
| notFormula (And x y) = Or (notFormula x) (notFormula y) | |||
| notFormula (Or x y) = And (notFormula x) (notFormula y) | |||
| newtype System a = FMap { getSystem :: Map Formula a } | |||
| deriving (Eq, Show, Ord) | |||
| emptySystem :: System a | |||
| emptySystem = FMap mempty | |||
| mapSystem :: System a -> (a -> b) -> System b | |||
| mapSystem (FMap x) f = FMap (fmap f x) | |||
| @ -0,0 +1,67 @@ | |||
| # This file was automatically generated by 'stack init' | |||
| # | |||
| # Some commonly used options have been documented as comments in this file. | |||
| # For advanced use and comprehensive documentation of the format, please see: | |||
| # https://docs.haskellstack.org/en/stable/yaml_configuration/ | |||
| # Resolver to choose a 'specific' stackage snapshot or a compiler version. | |||
| # A snapshot resolver dictates the compiler version and the set of packages | |||
| # to be used for project dependencies. For example: | |||
| # | |||
| # resolver: lts-3.5 | |||
| # resolver: nightly-2015-09-21 | |||
| # resolver: ghc-7.10.2 | |||
| # | |||
| # The location of a snapshot can be provided as a file or url. Stack assumes | |||
| # a snapshot provided as a file might change, whereas a url resource does not. | |||
| # | |||
| # resolver: ./custom-snapshot.yaml | |||
| # resolver: https://example.com/snapshots/2018-01-01.yaml | |||
| resolver: | |||
| url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/1.yaml | |||
| # User packages to be built. | |||
| # Various formats can be used as shown in the example below. | |||
| # | |||
| # packages: | |||
| # - some-directory | |||
| # - https://example.com/foo/bar/baz-0.0.2.tar.gz | |||
| # subdirs: | |||
| # - auto-update | |||
| # - wai | |||
| packages: | |||
| - . | |||
| # Dependency packages to be pulled from upstream that are not in the resolver. | |||
| # These entries can reference officially published versions as well as | |||
| # forks / in-progress versions pinned to a git hash. For example: | |||
| # | |||
| # extra-deps: | |||
| # - acme-missiles-0.3 | |||
| # - git: https://github.com/commercialhaskell/stack.git | |||
| # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a | |||
| # | |||
| # extra-deps: [] | |||
| # Override default flag values for local packages and extra-deps | |||
| # flags: {} | |||
| # Extra package databases containing global packages | |||
| # extra-package-dbs: [] | |||
| # Control whether we use the GHC we find on the path | |||
| # system-ghc: true | |||
| # | |||
| # Require a specific version of stack, using version ranges | |||
| # require-stack-version: -any # Default | |||
| # require-stack-version: ">=2.5" | |||
| # | |||
| # Override the architecture used by stack, especially useful on Windows | |||
| # arch: i386 | |||
| # arch: x86_64 | |||
| # | |||
| # Extra directories used by stack for building | |||
| # extra-include-dirs: [/path/to/dir] | |||
| # extra-lib-dirs: [/path/to/dir] | |||
| # | |||
| # Allow a newer minor version of GHC than the snapshot specifies | |||
| # compiler-check: newer-minor | |||
| @ -0,0 +1,13 @@ | |||
| # This file was autogenerated by Stack. | |||
| # You should not edit this file by hand. | |||
| # For more information, please see the documentation at: | |||
| # https://docs.haskellstack.org/en/stable/lock_files | |||
| packages: [] | |||
| snapshots: | |||
| - completed: | |||
| size: 563098 | |||
| url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/1.yaml | |||
| sha256: 395775c03e66a4286f134d50346b0b6f1432131cf542886252984b4cfa5fef69 | |||
| original: | |||
| url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/1.yaml | |||
| @ -0,0 +1,52 @@ | |||
| {- let | |||
| sym : (A : Type) (x y : A) -> Path (\x -> A) x y -> Path (\x -> A) y x | |||
| = λ A x y p i -> p (~ i) | |||
| in let | |||
| funext : (A : Type) (B : A -> Type) (f g : (x : A) -> B x) -> ((x : A) -> Path (\i -> B x) (f x) (g x)) -> Path (\i -> (x : A) -> B x) f g | |||
| = λ A B f g h i x -> h x i | |||
| in let | |||
| i0IsI1 : Path (\x -> I) i0 i1 | |||
| = λ i -> i | |||
| in let | |||
| singContr : (A : Type) (a b : A) (p : Path (\j -> A) a b) -> Path (\i -> (x : A) * (Path (\j -> A) a x)) (a, \i -> a) (b, p) | |||
| = λ A a b p i -> (p i, λ j -> p (i && j)) | |||
| in -} let | |||
| transport : (A : I -> Type) (a : A i0) -> A i1 | |||
| = \A a -> comp A i0 (\i -> []) a | |||
| in {- let | |||
| Jay : (A : Type) (x : A) | |||
| (P : (y : A) -> Path (\i -> A) x y -> Type) | |||
| (d : P x (\i -> x)) | |||
| (y : A) (p : Path (\i -> A) x y) | |||
| -> P y p | |||
| = \A x P d y p -> transport (\i -> P (p i) (\j -> p (i && j))) d | |||
| in -} | |||
| let | |||
| fill : (i : I) (A : I -> Type) | |||
| (phi : I) (u : (i : I) -> Partial phi (A i)) | |||
| -> Sub (A i0) phi (u i0) -> A i | |||
| = \i A phi u a0 -> | |||
| comp (\j -> A (i && j)) (phi || ~i) (\j -> [ phi -> u (i && j), ~i -> a0 ]) a0 | |||
| in let | |||
| trans : (A : Type) (a b c : A) | |||
| -> Path (\i -> A) a b | |||
| -> Path (\i -> A) b c | |||
| -> Path (\i -> A) a c | |||
| = \A a b c p q i -> | |||
| comp (\j -> A) (i || ~i) | |||
| (\j -> [ ~i -> a, i -> q j ]) | |||
| (p i) | |||
| in let | |||
| elimI : (P : I -> Type) | |||
| (a : P i0) | |||
| (b : P i1) | |||
| -> Path P a b | |||
| -> (i : I) -> P i | |||
| = \P a b p i -> p i | |||
| in let | |||
| contrI : (i : I) -> Path (\i -> I) i0 i | |||
| = \i -> elimI (\x -> Path (\i -> I) i0 x) (\i -> i0) (\i -> i) (\i j -> i && j) i | |||
| in let | |||
| IisContr : (i : I) * ((j : I) -> Path (\i -> I) i j) | |||
| = (i0, contrI) | |||
| in IisContr | |||