@ -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 |