cubical-0.2.0: Eval.hs
{-# LANGUAGE TupleSections, GeneralizedNewtypeDeriving #-}
module Eval ( eval
, evals
, app
, conv
, fstSVal
, Eval
, runEval
) where
import Control.Applicative
import Control.Arrow (second)
import Control.Monad
import Control.Monad.Reader
import Data.Functor.Identity
import Data.List
import Data.Maybe (fromMaybe)
import CTT
trace :: String -> Eval ()
trace s = do
debug <- ask
when debug $ liftIO (putStrLn s)
-- For now only store the debugging boolean
type EState = Bool
newtype Eval a = Eval { unEval :: ReaderT Bool IO a }
deriving (Functor, Applicative, Monad, MonadIO, MonadReader Bool)
runEval :: Bool -> Eval a -> IO a
runEval debug e = runReaderT (unEval e) debug
look :: Ident -> OEnv -> Eval (Binder, Val)
look x (OEnv (Pair rho (n@(y,l),u)) opaques)
| x == y = return (n, u)
| otherwise = look x (OEnv rho opaques)
look x r@(OEnv (PDef es r1) o) = case lookupIdent x es of
Just (y,t) -> (y,) <$> eval r t
Nothing -> look x (OEnv r1 o)
eval :: OEnv -> Ter -> Eval Val
eval e U = return VU
eval e (PN pn) = evalAppPN e pn []
eval e t@(App r s) = case unApps t of
(PN pn,us) -> evalAppPN e pn us
_ -> appM (eval e r) (eval e s)
eval e (Var i) = do
(x,v) <- look i e
return $ if x `elem` opaques e then VVar ("opaque_" ++ show x) $ support v else v
eval e (Pi a b) = VPi <$> eval e a <*> eval e b
eval e (Lam x t) = return $ Ter (Lam x t) e -- stop at lambdas
eval e (Sigma a b) = VSigma <$> eval e a <*> eval e b
eval e (SPair a b) = VSPair <$> eval e a <*> eval e b
eval e (Fst a) = fstSVal <$> eval e a
eval e (Snd a) = sndSVal <$> eval e a
eval e (Where t decls) = eval (oPDef False decls e) t
eval e (Con name ts) = VCon name <$> mapM (eval e) ts
eval e (Split pr alts) = return $ Ter (Split pr alts) e
eval e (Sum pr ntss) = return $ Ter (Sum pr ntss) e
evals :: OEnv -> [(Binder,Ter)] -> Eval [(Binder,Val)]
evals env = sequenceSnd . map (second (eval env))
fstSVal, sndSVal :: Val -> Val
fstSVal (VSPair a b) = a
fstSVal u | isNeutral u = VFst u
| otherwise = error $ show u ++ " should be neutral"
sndSVal (VSPair a b) = b
sndSVal u | isNeutral u = VSnd u
| otherwise = error $ show u ++ " should be neutral"
-- Application
app :: Val -> Val -> Eval Val
app (Ter (Lam x t) e) u = eval (oPair e (x,u)) t
app (Kan Com (VPi a b) box@(Box dir x v nvs)) u = do
trace "Pi Com"
ufill <- fill a (Box (mirror dir) x u [])
bcu <- cubeToBox ufill (shapeOfBox box)
comM (app b ufill) (appBox box bcu)
app kf@(Kan Fill (VPi a b) box@(Box dir i w nws)) v = do
trace "Pi fill"
let x = fresh (kf, v)
u <- v `face` (i,dir)
ufill <- fill a (Box (mirror dir) i u [])
bcu <- cubeToBox ufill (shapeOfBox box)
vfill <- fill a (Box (mirror dir) i u [((x,down),ufill),((x,up),v)])
vx <- fillM (app b ufill) (appBox box bcu)
vi0 <- appM (return w) (vfill `face` (i,mirror dir))
vi1 <- comM (app b ufill) (appBox box bcu)
nvs <- sequenceSnd [ ((n,d),appM (return ws) (vfill `face` (n,d)))
| ((n,d),ws) <- nws ]
comM (app b vfill) (return (Box up x vx (((i,mirror dir),vi0) : ((i,dir),vi1):nvs)))
-- app vext@(VExt x bv fv gv pv) w = do
-- -- NB: there are various choices how to construct this
-- let y = fresh (vext, w)
-- w0 <- w `face` (x,down)
-- left <- app fv w0
-- right <- app gv (swap w x y)
-- pvxw <- appNameM (app pv w0) x
-- comM (app bv w) (return (Box up y pvxw [((x,down),left),((x,up),right)]))
app vhext@(VHExt x bv fv gv pv) w = do
a0 <- w `face` (x,down)
a1 <- w `face` (x,up)
appNameM (apps pv [a0, a1, Path x w]) x
app (Ter (Split _ nvs) e) (VCon name us) = case lookup name nvs of
Just (xs,t) -> eval (upds e (zip xs us)) t
Nothing -> error $ "app: Split with insufficient arguments; " ++
"missing case for " ++ name
app u@(Ter (Split _ _) _) v
| isNeutral v = return $ VSplit u v -- v should be neutral
| otherwise = error $ "app: (VSplit) " ++ show v ++ " is not neutral"
app r s
| isNeutral r = return $ VApp r s -- r should be neutral
| otherwise = error $ "app: (VApp) " ++ show r ++ " is not neutral"
-- Monadic version of app
appM :: Eval Val -> Eval Val -> Eval Val
appM t1 t2 = do
u <- t1
v <- t2
app u v
apps :: Val -> [Val] -> Eval Val
apps = foldM app
appBox :: Box Val -> Box Val -> Eval (Box Val)
appBox (Box dir x v nvs) (Box _ _ u nus) = do
let lookup' x = fromMaybe (error "appBox") . lookup x
sequenceBox $ Box dir x (app v u) [ (nnd,app v (lookup' nnd nus))
| (nnd,v) <- nvs ]
appName :: Val -> Name -> Eval Val
appName (Path x u) y | y `elem` [0,1] = u `face` (x,y)
appName p y | y `elem` [0,1] = return $ VAppName p y
-- p has to be neutral
appName (Path x u) y | x == y = return u
| y `elem` support u = error ("appName " ++ "\nu = " ++
show u ++ "\ny = " ++ show y)
| otherwise = return $ swap u x y
appName v y = return $ VAppName v y
appNameM :: Eval Val -> Name -> Eval Val
appNameM v n = do
v' <- v
appName v' n
-- Apply a primitive notion
evalAppPN :: OEnv -> PN -> [Ter] -> Eval Val
evalAppPN e pn ts
| length ts < arity pn =
-- Eta expand primitive notions
let r = arity pn - length ts
binders = map (\n -> '_' : show n) [1..r]
vars = map Var binders
in return $ Ter (mkLams binders $ mkApps (PN pn) (ts ++ vars)) e
| otherwise = do
let (args,rest) = splitAt (arity pn) ts
vas <- mapM (eval e) args
p <- evalPN (freshs e) pn vas
r <- mapM (eval e) rest
apps p r
-- Evaluate primitive notions
evalPN :: [Name] -> PN -> [Val] -> Eval Val
evalPN (x:_) Id [a,a0,a1] = return $ VId (Path x a) a0 a1
evalPN (x:_) IdP [_,_,p,a0,a1] = return $ VId p a0 a1
evalPN (x:_) Refl [_,a] = return $ Path x a
evalPN (x:_) TransU [_,_,p,t] =
comM (appName p x) (return (Box up x t []))
evalPN (x:_) TransInvU [_,_,p,t] =
comM (appName p x) (return (Box down x t []))
evalPN (x:_) TransURef [a,t] = Path x <$> fill a (Box up x t [])
evalPN (x:_) TransUEquivEq [_,b,f,_,_,u] = do
fu <- app f u
Path x <$> fill b (Box up x fu []) -- TODO: Check this!
evalPN (x:y:_) CSingl [a,u,v,p] = do
pv <- appName p y
theta <- fill a (Box up y u [((x,down),u),((x,up),pv)])
omega <- theta `face` (y,up)
return $ Path x (VSPair omega (Path y theta))
-- evalPN (x:_) Ext [_,b,f,g,p] = return $ Path x $ VExt x b f g p
evalPN (x:_) HExt [_,b,f,g,p] = return $ Path x $ VHExt x b f g p
evalPN _ Inh [a] = return $ VInh a
evalPN _ Inc [_,t] = return $ VInc t
evalPN (x:_) Squash [_,r,s] = return $ Path x $ VSquash x r s
evalPN _ InhRec [_,b,p,phi,a] = inhrec b p phi a
evalPN (x:_) EquivEq [a,b,f,s,t] = return $ Path x $ VEquivEq x a b f s t
evalPN (x:y:_) EquivEqRef [a,s,t] =
return $ Path y $ Path x $ VEquivSquare x y a s t
evalPN (x:_) MapOnPath [_,_,f,_,_,p] =
Path x <$> appM (return f) (appName p x)
evalPN (x:_) MapOnPathD [_,_,f,_,_,p] =
Path x <$> appM (return f) (appName p x)
evalPN (x:_) AppOnPath [_,_,_,_,_,_,p,q] =
Path x <$> appM (appName p x) (appName q x)
evalPN (x:_) MapOnPathS [_,_,_,f,_,_,p,_,_,q] =
Path x <$> appM (appM (pure f) (appName p x)) (appName q x)
evalPN _ Circle [] = return VCircle
evalPN _ Base [] = return VBase
evalPN (x:_) Loop [] = return $ Path x $ VLoop x
evalPN _ CircleRec [f,b,l,s] = circlerec f b l s
evalPN _ I [] = return VI
evalPN _ I0 [] = return VI0
evalPN _ I1 [] = return VI1
evalPN (x:_) Line [] = return $ Path x $ VLine x
evalPN _ IntRec [f,s,e,l,u] = intrec f s e l u
evalPN _ u _ = error ("evalPN " ++ show u)
appS1 :: Val -> Val -> Name -> Eval Val
appS1 f p x | x `elem` [0,1] = appName p x
appS1 f p x = do
let y = fresh (p,(f,x))
q <- appName p y
a <- appName p 0
b <- appName p 1
newBox <- Box down y b <$>
sequenceSnd [ ((x,down),q `face` (x,down))
, ((x,up),b `face` (x,up))]
fb <- app f VBase
fl <- app f (VLoop y)
tu <- fillM (return VU) (Box down y fb <$>
sequenceSnd [ ((x,down),fl `face` (x,down))
, ((x,up),fb `face` (x,up))])
com tu newBox
-- Compute the face of an environment
faceEnv :: OEnv -> Side -> Eval OEnv
faceEnv e xd = mapOEnvM (`face` xd) e
faceName :: Name -> Side -> Name
faceName 0 _ = 0
faceName 1 _ = 1
faceName x (y,d) | x == y = d
| otherwise = x
-- Compute the face of a value
face :: Val -> Side -> Eval Val
face u xdir@(x,dir) =
let fc v = v `face` xdir in case u of
VU -> return VU
Ter t e -> do e' <- e `faceEnv` xdir
eval e' t
VId a v0 v1 -> VId <$> fc a <*> fc v0 <*> fc v1
Path y v | x == y -> return u
| otherwise -> Path y <$> fc v
-- VExt y b f g p | x == y && dir == down -> return f
-- | x == y && dir == up -> return g
-- | otherwise ->
-- VExt y <$> fc b <*> fc f <*> fc g <*> fc p
VHExt y b f g p | x == y && dir == down -> return f
| x == y && dir == up -> return g
| otherwise ->
VHExt y <$> fc b <*> fc f <*> fc g <*> fc p
VPi a f -> VPi <$> fc a <*> fc f
VSigma a f -> VSigma <$> fc a <*> fc f
VSPair a b -> VSPair <$> fc a <*> fc b
VInh v -> VInh <$> fc v
VInc v -> VInc <$> fc v
VSquash y v0 v1 | x == y && dir == down -> return v0
| x == y && dir == up -> return v1
| otherwise -> VSquash y <$> fc v0 <*> fc v1
VCon c us -> VCon c <$> mapM fc us
VEquivEq y a b f s t | x == y && dir == down -> return a
| x == y && dir == up -> return b
| otherwise ->
VEquivEq y <$> fc a <*> fc b <*> fc f <*> fc s <*> fc t
VPair y a v | x == y && dir == down -> return a
| x == y && dir == up -> fc v
| otherwise -> VPair y <$> fc a <*> fc v
VEquivSquare y z a s t | x == y -> return a
| x == z && dir == down -> return a
| x == z && dir == up -> do
let idV = Ter (Lam (noLoc "x") (Var "x")) oEmpty
return $ VEquivEq y a a idV s t
| otherwise ->
VEquivSquare y z <$> fc a <*> fc s <*> fc t
VSquare y z v | x == y -> fc v
| x == z && dir == down -> fc v
| x == z && dir == up -> do
v' <- fc v
VPair y <$> v' `face` (y,down) <*> pure v'
| otherwise -> VSquare y z <$> fc v
Kan Fill a b@(Box dir' y v nvs)
| x /= y && x `notElem` nonPrincipal b -> fillM (fc a) (mapBoxM fc b)
| x `elem` nonPrincipal b -> return $ lookBox (x,dir) b
| x == y && dir == mirror dir' -> return v
| otherwise -> com a b
VFillN a b@(Box dir' y v nvs)
| x /= y && x `notElem` nonPrincipal b -> fillM (fc a) (mapBoxM fc b)
| x `elem` nonPrincipal b -> return $ lookBox (x,dir) b
| x == y && dir == mirror dir' -> return v
| otherwise -> com a b
Kan Com a b@(Box dir' y v nvs)
| x == y -> return u
| x `notElem` nonPrincipal b -> comM (fc a) (mapBoxM fc b)
| x `elem` nonPrincipal b -> lookBox (x,dir) b `face` (y,dir')
VComN a b@(Box dir' y v nvs)
| x == y -> return u
| x `notElem` nonPrincipal b -> comM (fc a) (mapBoxM fc b)
| x `elem` nonPrincipal b -> lookBox (x,dir) b `face` (y,dir')
VComp b@(Box dir' y _ _)
| x == y -> return u
| x `notElem` nonPrincipal b -> VComp <$> mapBoxM fc b
| x `elem` nonPrincipal b -> lookBox (x,dir) b `face` (y,dir')
VFill z b@(Box dir' y v nvs)
| x == z -> return u
| x /= y && x `notElem` nonPrincipal b -> VFill z <$> mapBoxM fc b
| (x,dir) `elem` defBox b ->
lookBox (x,dir) <$> mapBoxM (`face` (z,down)) b
| x == y && dir == dir' ->
VComp <$> mapBoxM (`face` (z,up)) b
VInhRec b p h a -> join $ inhrec <$> fc b <*> fc p <*> fc h <*> fc a
VApp u v -> appM (fc u) (fc v)
VAppName u n -> do
trace ("face " ++ "\nxdir " ++ show xdir ++
"\nu " ++ show u ++ "\nn " ++ show n)
appNameM (fc u) (faceName n xdir)
VSplit u v -> appM (fc u) (fc v)
VVar s d -> return $ VVar s [ faceName n xdir | n <- d ]
VFst p -> fstSVal <$> fc p
VSnd p -> sndSVal <$> fc p
VCircle -> return VCircle
VBase -> return VBase
VLoop y | x == y -> return VBase
| otherwise -> return $ VLoop y
VCircleRec f b l s -> join $ circlerec <$> fc f <*> fc b <*> fc l <*> fc s
VI -> return VI
VI0 -> return VI0
VI1 -> return VI1
VLine y
| x == y && dir == down -> return VI0
| x == y && dir == up -> return VI1
| otherwise -> return $ VLine y
VIntRec f s e l u -> join $ intrec <$> fc f <*> fc s <*> fc e <*> fc l <*> fc u
faceM :: Eval Val -> Side -> Eval Val
faceM t xdir = do
v <- t
v `face` xdir
unCompAs :: Val -> Name -> Box Val
unCompAs (VComp box) y = swap box (pname box) y
unCompAs v _ = error $ "unCompAs: " ++ show v ++ " is not a VComp"
unFillAs :: Val -> Name -> Box Val
unFillAs (VFill x box) y = swap box x y
unFillAs v _ = error $ "unFillAs: " ++ show v ++ " is not a VFill"
-- p(x) = <z>q(x,z)
-- a(x) = q(x,0) b(x) = q(x,1)
-- q(0,y) connects a(0) and b(0)
-- we connect q(0,0) to q(1,1)
-- appDiag :: Val -> Val -> Name -> Val
-- appDiag tu p x | x `elem` [0,1] = appName p x
-- appDiag tu p x =
-- traceb ("appDiag " ++ "\ntu = " ++ show tu ++ "\np = " ++ show p ++ "\nx = "
-- -- ++ show x ++ " " ++ show y
-- -- ++ "\nq = " ++ show q) -- "\nnewBox =" ++ show newBox)
-- com tu newBox
-- where y = fresh (p,(tu,x))
-- q = appName p y
-- a = appName p 0
-- b = appName p 1
-- newBox = Box down y b [((x,down),q `face` (x,down)),((x,up),b `face` (x,up))]
cubeToBox :: Val -> Box () -> Eval (Box Val)
cubeToBox v = modBoxM (\nd _ -> v `face` nd)
inhrec :: Val -> Val -> Val -> Val -> Eval Val
inhrec _ _ phi (VInc a) = app phi a
inhrec b p phi (VSquash x a0 a1) = do
let fc w d = w `face` (x,d)
b0 <- join $ inhrec <$> fc b down <*> fc p down <*> fc phi down <*> pure a0
b1 <- join $ inhrec <$> fc b up <*> fc p up <*> fc phi up <*> pure a1
let z = fresh [b,p,phi,b0,b1]
b0fill <- fill b (Box up x b0 [])
b0fillx1 <- b0fill `face` (x, up)
right <- appNameM (appM (appM (fc p up) (return b0fillx1)) (return b1)) z
com b (Box up z b0fill [((x,down),b0),((x,up),right)])
inhrec b p phi (Kan ktype (VInh a) box) = do
let irec (j,dir) v = let fc v = v `face` (j,dir)
in join $ inhrec <$> fc b <*> fc p <*> fc phi <*> pure v
box' <- modBoxM irec box
kan ktype b box'
inhrec b p phi v = return $ VInhRec b p phi v -- v should be neutral
circlerec :: Val -> Val -> Val -> Val -> Eval Val
circlerec _ b _ VBase = return b
circlerec f b l v@(VLoop x) = do
let y = fresh [f,b,l,v]
pxy <- appName l y
theta <- connection VCircle x y v
a <- app f theta
px1 <- pxy `face` (y,up)
p11 <- px1 `face` (x,up)
p0y <- pxy `face` (x,down)
trace ("circlerec " ++ "\nf = " ++ show f ++ "\nl = " ++
show l ++ "\nx = " ++ show x)
com a (Box down y px1 [((x,down),p0y),((x,up),p11)])
circlerec f b l v@(Kan ktype VCircle box) = do
let crec side u = let fc w = w `face` side
in join $ circlerec <$> fc f <*> fc b <*> fc l <*> pure u
fv <- app f v
box' <- modBoxM crec box
kan ktype fv box'
circlerec f b l v = return $ VCircleRec f b l v -- v should be neutral
-- Assumes y is fresh and x fresh for a; constructs a connection
-- square with faces u (x), u (y), u (1), u (1).
connection :: Val -> Name -> Name -> Val -> Eval Val
connection a x y u = do
u1 <- u `face` (x,up)
ufill <- fill a (Box down y u1 [((x,down), swap u x y), ((x,up),u1)])
let z = fresh ([x,y], [a,u])
ufillzy = swap ufill x z
ufillzx = swap ufillzy y x
com a (Box down z u1 [ ((x,down),ufillzy), ((x,up),u1)
, ((y,down),ufillzx), ((y,up),u1)])
intrec :: Val -> Val -> Val -> Val -> Val -> Eval Val
intrec _ s _ _ VI0 = return s
intrec _ _ e _ VI1 = return e
intrec f s e l v@(VLine x) = do
let y = fresh [f,s,e,l,v]
pxy <- appName l y
theta <- connection VI x y v
a <- app f theta
px1 <- pxy `face` (y,up)
p11 <- px1 `face` (x,up)
p0y <- pxy `face` (x,down)
com a (Box down y px1 [((x,down),p0y),((x,up),p11)])
intrec f s e l v@(Kan ktype VCircle box) = do
let irec side u = let fc w = w `face` side
in join $ intrec <$> fc f <*> fc s <*>
fc e <*> fc l <*> pure u
fv <- app f v
box' <- modBoxM irec box
kan ktype fv box'
intrec f s e l v = return $ VIntRec f s e l v -- v should be neutral
kan :: KanType -> Val -> Box Val -> Eval Val
kan Fill = fill
kan Com = com
isNeutralFill :: Val -> Box Val -> Eval Bool
isNeutralFill v box | isNeutral v = return True
isNeutralFill v@(Ter (PN (Undef _)) _) box = return True
isNeutralFill (Ter (Sum _ _) _) (Box _ _ v nvs) =
return $ isNeutral v || or [ isNeutral u | (_,u) <- nvs ]
isNeutralFill v@(Kan Com VU tbox') box@(Box d x _ _) = do
let nK = nonPrincipal tbox'
nJ = nonPrincipal box
nL = nJ \\ nK
aDs = if x `elem` nK then allDirs nL else (x,mirror d):allDirs nL
return $ or [ isNeutral (lookBox yc box) | yc <- aDs ]
isNeutralFill v@(Kan Fill VU tbox) box =
return $ or [ isNeutral (lookBox yc box) | yc <- defBox box \\ defBox tbox ]
isNeutralFill v@(VEquivSquare y z _ _ _) box@(Box d x _ _) = do
let nJ = nonPrincipal box
nL = nJ \\ [y,z]
aDs = if x `elem` [y,z] then allDirs nL else (x,mirror d) : allDirs nL
return $ or [ isNeutral (lookBox yc box) | yc <- aDs ]
isNeutralFill v@(VEquivEq z a b f s t) box@(Box d x vx nxs)
| d == down && z == x = isNeutral <$> app s vx
| otherwise = do -- TODO: check
let nJ = nonPrincipal box
nL = nJ \\ [z]
aDs = if x == z then allDirs nL else (x,mirror d) : allDirs nL
return $ or [ isNeutral (lookBox yc box) | yc <- aDs ]
isNeutralFill v box = return False
-- Monadic version of fill
fillM :: Eval Val -> Eval (Box Val) -> Eval Val
fillM v b = do
v' <- v
b' <- b
fill v' b'
fills :: [(Binder,Ter)] -> OEnv -> [Box Val] -> Eval [Val]
fills [] _ [] = return []
fills ((x,a):as) e (box:boxes) = do
v <- fillM (eval e a) (return box)
vs <- fills as (oPair e (x,v)) boxes
return $ v : vs
fills _ _ _ = error "fills: different lengths of types and values"
unPack :: Name -> Name -> (Name,Dir) -> Val -> Val
unPack x y (z,c) v | z /= x && z /= y = unSquare v
| z == y && c == up = sndVal v
| otherwise = v
-- Kan filling
fill :: Val -> Box Val -> Eval Val
fill v box = do
b <- isNeutralFill v box
if b then return $ VFillN v box else fill' v box
fill' vid@(VId a v0 v1) box@(Box dir i v nvs) = do
let x = fresh (vid, box)
box' <- consBox (x,(v0,v1)) <$> mapBoxM (`appName` x) box
Path x <$> fillM (a `appName` x) (return box')
fill' (VSigma a f) box@(Box dir x v nvs) = do
u <- fill a (mapBox fstSVal box)
VSPair u <$> fillM (app f u) (return (mapBox sndSVal box))
-- assumes cvs are constructor vals
fill' v@(Ter (Sum _ nass) env) box@(Box _ _ (VCon n _) _) = case getIdent n nass of
Just as -> do
let boxes = transposeBox $ mapBox unCon box
-- fill boxes for each argument position of the constructor
VCon n <$> fills as env boxes
Nothing -> error $ "fill: missing constructor in labelled sum " ++ n
fill' (VEquivSquare x y a s t) box@(Box dir x' vx' nvs) =
VSquare x y <$> fill a (modBox (unPack x y) box)
fill' veq@(VEquivEq x a b f s t) box@(Box dir z vz nvs)
| x /= z && x `notElem` nonPrincipal box = do
trace "VEquivEq case 1"
ax0 <- fill a (mapBox fstVal box)
bx0 <- app f ax0
let bx = mapBox sndVal box
bx' <- mapBoxM (`face` (x,up)) bx
bx1 <- fill b bx' --- independent of x
v <- fill b $ (x,(bx0,bx1)) `consBox` bx
return $ VPair x ax0 v
| x /= z && x `elem` nonPrincipal box = do
trace "VEquivEq case 2"
let ax0 = lookBox (x,down) box
-- modification function
mf (ny,dy) vy | x /= ny = return (sndVal vy)
| dy == down = app f ax0
| otherwise = return vy
bx <- sequenceBox $ modBox mf box
VPair x ax0 <$> fill b bx
| x == z && dir == up = do
trace "VEquivEq case 3"
let ax0 = vz
bx0 <- app f ax0
v <- fill b $ Box dir z bx0 [ (nnd,sndVal v) | (nnd,v) <- nvs ]
return $ VPair x ax0 v
| x == z && dir == down = do
trace "VEquivEq case 4"
gbsb <- app s vz
let (gb,sb) = (fstSVal gbsb, sndSVal gbsb)
y = fresh (veq, box)
vy <- appName sb x
let vpTSq :: Name -> Dir -> Val -> Eval (Val,Val)
vpTSq nz dz (VPair z a0 v0) = do
let vp = VSPair a0 (Path z v0)
t0 <- t `face` (nz,dz)
b0 <- vz `face` (nz,dz)
l0sq0 <- appNameM (appM (app t0 b0) (return vp)) y
let (l0,sq0) = (fstSVal l0sq0, sndSVal l0sq0)
sq0x <- appName sq0 x
return (l0,sq0x) -- TODO: check the correctness of the square s0
-- TODO: Use modBox!
vsqs <- sequenceSnd [ ((n,d),vpTSq n d v) | ((n,d),v) <- nvs]
let box1 = Box up y gb [ (nnd,v) | (nnd,(v,_)) <- vsqs ]
afill <- fill a box1
acom <- afill `face` (y,up)
fafill <- app f afill
let box2 = Box up y vy (((x,down),fafill) : ((x,up),vz) :
[ (nnd,v) | (nnd,(_,v)) <- vsqs ])
bcom <- com b box2
return $ VPair x acom bcom
| otherwise = error "fill EqEquiv"
fill' v@(Kan Com VU tbox') box@(Box dir x' vx' nvs')
| toAdd /= [] = do -- W.l.o.g. assume that box contains faces for
-- the non-principal sides of tbox.
trace "Kan Com 1"
let -- TODO: Is this correct? Do we have to consider the auxsides?
add :: Side -> Eval Val
add yc = do box' <- mapBoxM (`face` yc) box
fillM (lookBox yc tbox `face` (x,tdir)) (return box')
-- Note: This could be done nicer by providing a monad instance for (,)
sides' <- sequence [ do m1 <- add (n,down)
m2 <- add (n,up)
return (n,(m1,m2)) | n <- toAdd ]
fill v (sides' `appendBox` box)
| x' `notElem` nK = do
trace "Kan Com 2"
principal <- fill tx (mapBox (pickout (x,tdir')) boxL)
nonprincipal <-
sequence [ do pyc <- principal `face` yc
let side = [((x,tdir),lookBox yc box),((x,tdir'),pyc)]
v' <- fill (lookBox yc tbox)
(side `appendSides` mapBox (pickout yc) boxL)
return (yc,v')
| yc <- allDirs nK ]
return $ VComp (Box tdir x principal nonprincipal)
| x' `elem` nK = do
trace "Kan Com 3"
let -- assumes zc in defBox tbox
auxsides zc = [ (yd,pickout zc (lookBox yd box)) | yd <- allDirs nL ]
-- extend input box along x with orientation tdir'; results
-- in the non-principal faces on the intersection of defBox
-- box and defBox tbox; note, that the intersection contains
-- (x',dir'), but not (x',dir) (and (x,_))
npintbox <- modBoxM (\yc boxside -> fill (lookBox yc tbox)
(Box tdir' x boxside (auxsides yc)))
(subBox (nK `intersect` nJ) box)
npintfacebox <- mapBoxM (`face` (x,tdir')) npintbox
principal <- fill tx (auxsides (x,tdir') `appendSides` npintfacebox)
nplp <- principal `face` (x',dir)
fnpintboxs <- sequence [ do fv <- v `face` (x',dir)
return (yc,fv)
| (yc,v) <- sides npintbox ]
let nplnp = auxsides (x',dir) ++ fnpintboxs
-- the missing non-principal face on side (x',dir)
v' <- fill (lookBox (x',dir) tbox) (Box tdir x nplp nplnp)
let nplast = ((x',dir),v')
return $ VComp (Box tdir x principal (nplast:fromBox npintbox))
where nK = nonPrincipal tbox
nJ = nonPrincipal box
z = fresh (tbox', box)
-- x is z
tbox@(Box tdir x tx nvs) = swap tbox' (pname tbox') z
toAdd = nK \\ (x' : nJ)
nL = nJ \\ nK
boxL = subBox nL box
dir' = mirror dir
tdir' = mirror tdir
-- asumes zd is in the sides of tbox
pickout zd vcomp = lookBox zd (unCompAs vcomp z)
fill' v@(Kan Fill VU tbox@(Box tdir x tx nvs)) box@(Box dir x' vx' nvs')
-- the cases should be (in order):
-- 1) W.l.o.g. K subset x', J
-- 2) x' = x & dir = tdir
-- 3) x' = x & dir = mirror tdir
-- 4) x `notElem` J (maybe combine with 1?)
-- 5) x' `notElem` K
-- 6) x' `elem` K
| toAdd /= [] = do
trace "Kan Fill VU Case 1" -- W.l.o.g. nK subset x':nJ
let add :: Side -> Eval Val
add zc = fillM (return (lookBox zc tbox)) (mapBoxM (`face` zc) box)
newSides <- sequenceSnd [ (zc,add zc) | zc <- allDirs toAdd ]
fill v (newSides `appendSides` box)
| x == x' && dir == tdir = do -- assumes K subset x',J
trace "Kan Fill VU Case 2"
let boxp = lookBox (x,dir') box -- is vx'
principal <- fill (lookBox (x',tdir') tbox)
(Box up z boxp (auxsides (x',tdir')))
nonprincipal <-
sequenceSnd [ (zc,do let principzc = lookBox zc box
fpzc <- principal `face` zc
-- "degenerate" along z!
ppzc <- principzc `face` (x,tdir)
let sides = [((x,tdir'),fpzc),((x,tdir),ppzc)]
fill (lookBox zc tbox)
(Box up z principzc (sides ++ auxsides zc)))
| zc <- allDirs nK ]
return $ VFill z (Box tdir x principal nonprincipal)
| x == x' && dir == mirror tdir = do -- assumes K subset x',J
trace "Kan Fill VU Case 3"
let -- the principal side of box must be a VComp
-- should be safe given the neutral test at the beginning
upperbox = unCompAs (lookBox (x,dir') box) x
nonprincipal <- sequenceSnd
[ (zc,do let top = lookBox zc upperbox
bottom = lookBox zc box
princ <- top `face` (x,tdir) -- same as: bottom `face` (x,tdir)
let sides = [((z,down),bottom),((z,up),top)]
fill (lookBox zc tbox) (Box tdir' x princ -- "degenerate" along z!
(sides ++ auxsides zc)))
| zc <- allDirs nK ]
nonprincipalfaces <- sequenceSnd [ (zc,u `face` (x,dir))
| (zc,u) <- nonprincipal ]
principal <- fill (lookBox (x,tdir') tbox)
(Box up z (lookBox (x,tdir') upperbox)
(nonprincipalfaces ++ auxsides (x,tdir')))
return $ VFill z (Box tdir x principal nonprincipal)
| x `notElem` nJ = do -- assume x /= x' and K subset x', J
trace "Kan Fill VU Case 4"
comU <- v `face` (x,tdir) -- Kan Com VU (tbox (z=up))
let fcbox = mapBoxM (`face` (x,tdir)) box
xsides <- sequenceSnd [ ((x,tdir), fillM (return comU) fcbox)
, ((x,tdir'),
fillM (return (lookBox (x,tdir') tbox)) fcbox) ]
fill v (xsides `appendSides` box)
| x' `notElem` nK = do -- assumes x,K subset x',J
trace "Kan Fill VU Case 5"
let -- TODO: Do we need a fresh name? (Probably not: doesn't depend on x!)
xaux = unCompAs (lookBox (x,tdir) box) x
boxprinc = unFillAs (lookBox (x',dir') box) z
princnp = [((z,up),lookBox (x,tdir') xaux),((z,down),lookBox (x,tdir') box)]
++ auxsides (x,tdir')
principal <- fill (lookBox (x,tdir') tbox) -- tx
(Box dir x' (lookBox (x,tdir') boxprinc) princnp)
nonprincipal <- sequence
[ do let yup = lookBox yc xaux
fyup <- yup `face` (x,tdir)
fpyc <- principal `face` yc
let np = [ ((z,up),yup), ((z,down),lookBox yc box)
, ((y,c), fyup) -- deg along z!
, ((y,mirror c), fpyc) ] ++ auxsides yc
fb <- fill (lookBox yc tbox) (Box dir x' (lookBox yc boxprinc) np)
return (yc, fb)
| yc@(y,c) <- allDirs nK]
return $ VFill z (Box tdir x principal nonprincipal)
| x' `elem` nK = do -- assumes x,K subset x',J
trace "Kan Fill VU Case 6"
-- surprisingly close to the last case of the Kan-Com-VU filling
let upperbox = unCompAs (lookBox (x,dir') box) x
npintbox <- modBoxM (\zc downside ->
let bottom = lookBox zc box
top = lookBox zc upperbox
princ = downside -- same as bottom `face` (x',tdir) and
-- top `face` (x',tdir)
sides = [((z,down),bottom),((z,up),top)]
in fill (lookBox zc tbox) (Box tdir' x princ -- deg along z!
(sides ++ auxsides zc)))
(subBox (nK `intersect` nJ) box)
let npint = fromBox npintbox
npintfacebox <- mapBoxM (`face` (x,tdir)) npintbox
let principalbox = ([ ((z,down),lookBox (x,tdir') box)
, ((z,up) ,lookBox (x,tdir') upperbox)]
++ auxsides (x,tdir'))
`appendSides` npintfacebox
principal <- fill tx principalbox
let nplp = lookBox (x',dir) upperbox
nplnp <- sequenceSnd $
[ ((x',dir), nplp `face` (x',dir)) -- deg along z!
, ((x', dir'),principal `face` (x',dir)) ]
++ map (second return) (auxsides (x',dir))
++ [ (zc,u `face` (x',dir)) | (zc,u) <- sides npintbox ]
fb <- fill (lookBox (x',dir) tbox) (Box down z nplp nplnp)
return $ VFill z (Box tdir x principal (((x',dir),fb) : npint))
where z = fresh (v, box)
nK = nonPrincipal tbox
nJ = nonPrincipal box
toAdd = nK \\ (x' : nJ)
nL = nJ \\ (x : nK)
dir' = mirror dir
tdir' = mirror tdir
-- asumes zc is in the sides of tbox
pickout zc vfill = lookBox zc (unFillAs vfill z)
-- asumes zc is in the sides of tbox
auxsides zc = [ (yd,pickout zc (lookBox yd box)) | yd <- allDirs nL ]
fill' v b = return $ Kan Fill v b
-- Composition (ie., the face of fill which is created)
com :: Val -> Box Val -> Eval Val
com u box = do
b <- isNeutralFill u box
if b then return $ VComN u box else com' u box
com' vid@VId{} box@(Box dir i _ _) = fill vid box `faceM` (i,dir)
com' vsigma@VSigma{} box@(Box dir i _ _) = fill vsigma box `faceM` (i,dir)
com' veq@VEquivEq{} box@(Box dir i _ _) = fill veq box `faceM` (i,dir)
com' u@(Kan Com VU _) box@(Box dir i _ _) = fill u box `faceM` (i,dir)
com' u@(Kan Fill VU _) box@(Box dir i _ _) = fill u box `faceM` (i,dir)
com' ter@Ter{} box@(Box dir i _ _) = fill ter box `faceM` (i,dir)
com' v box = return $ Kan Com v box
-- Monadic version of com
comM :: Eval Val -> Eval (Box Val) -> Eval Val
comM t b = do
v <- t
b' <- b
com v b'
-- Conversion functions
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
(<&&>) = liftM2 (&&)
(<==>) :: (Monad m, Eq a) => a -> a -> m Bool
a <==> b = return (a == b)
andM :: [Eval Bool] -> Eval Bool
andM = liftM and . sequence
conv :: Int -> Val -> Val -> Eval Bool
conv k VU VU = return True
conv k (Ter (Lam x u) e) (Ter (Lam x' u') e') = do
let v = mkVar k $ support (e, e')
convM (k+1) (eval (oPair e (x,v)) u) (eval (oPair e' (x',v)) u')
conv k (Ter (Lam x u) e) u' = do
let v = mkVar k $ support e
convM (k+1) (eval (oPair e (x,v)) u) (app u' v)
conv k u' (Ter (Lam x u) e) = do
let v = mkVar k $ support e
convM (k+1) (app u' v) (eval (oPair e (x,v)) u)
conv k (Ter (Split p _) e) (Ter (Split p' _) e') =
liftM ((p == p') &&) $ convEnv k e e'
conv k (Ter (Sum p _) e) (Ter (Sum p' _) e') =
((p == p') &&) <$> convEnv k e e'
conv k (Ter (PN (Undef p)) e) (Ter (PN (Undef p')) e') =
liftM ((p == p') &&) $ convEnv k e e'
conv k (VPi u v) (VPi u' v') = do
let w = mkVar k $ support [u,u',v,v']
conv k u u' <&&> convM (k+1) (app v w) (app v' w)
conv k (VSigma u v) (VSigma u' v') = do
let w = mkVar k $ support [u,u',v,v']
conv k u u' <&&> convM (k+1) (app v w) (app v' w)
conv k (VId a u v) (VId a' u' v') = andM [conv k a a', conv k u u', conv k v v']
conv k (Path x u) (Path x' u') = conv k (swap u x z) (swap u' x' z)
where z = fresh (u,u')
conv k (Path x u) p' = convM k (return (swap u x z)) (appName p' z)
where z = fresh u
conv k p (Path x' u') = convM k (appName p z) (return (swap u' x' z))
where z = fresh u'
-- conv k (VExt x b f g p) (VExt x' b' f' g' p') =
-- andM [x <==> x', conv k b b', conv k f f', conv k g g', conv k p p']
conv k (VHExt x b f g p) (VHExt x' b' f' g' p') =
andM [x <==> x', conv k b b', conv k f f', conv k g g', conv k p p']
conv k (VFst u) (VFst u') = conv k u u'
conv k (VSnd u) (VSnd u') = conv k u u'
conv k (VInh u) (VInh u') = conv k u u'
conv k (VInc u) (VInc u') = conv k u u'
conv k (VSquash x u v) (VSquash x' u' v') =
andM [x <==> x', conv k u u', conv k v v']
conv k (VCon c us) (VCon c' us') =
liftM (\bs -> (c == c') && and bs) (zipWithM (conv k) us us')
conv k (Kan Fill v box) (Kan Fill v' box') =
conv k v v' <&&> convBox k box box'
conv k (Kan Com v box) (Kan Com v' box') =
andM [conv k v v', convBox k (swap box x y) (swap box' x' y)]
where y = fresh ((v,v'),(box,box'))
(x,x') = (pname box, pname box')
conv k (VComN v box) (VComN v' box') =
andM [conv k v v', convBox k (swap box x y) (swap box' x' y)]
where y = fresh ((v,v'),(box,box'))
(x,x') = (pname box, pname box')
conv k (VFillN v box) (VFillN v' box') =
andM [conv k v v', convBox k (swap box x y) (swap box' x' y)]
where y = fresh ((v,v'),(box,box'))
(x,x') = (pname box, pname box')
conv k (VEquivEq x a b f s t) (VEquivEq x' a' b' f' s' t') =
andM [x <==> x', conv k a a', conv k b b',
conv k f f', conv k s s', conv k t t']
conv k (VEquivSquare x y a s t) (VEquivSquare x' y' a' s' t') =
andM [x <==> x', y <==> y', conv k a a', conv k s s', conv k t t']
conv k (VPair x u v) (VPair x' u' v') =
andM [x <==> x', conv k u u', conv k v v']
conv k (VSquare x y u) (VSquare x' y' u') =
andM [x <==> x', y <==> y', conv k u u']
conv k (VComp box) (VComp box') =
convBox k (swap box x y) (swap box' x' y)
where y = fresh (box,box')
(x,x') = (pname box, pname box')
conv k (VFill x box) (VFill x' box') =
convBox k (swap box x y) (swap box' x' y)
where y = fresh (box,box')
conv k (VSPair u v) (VSPair u' v') = conv k u u' <&&> conv k v v'
conv k (VSPair u v) w =
conv k u (fstSVal w) <&&> conv k v (sndSVal w)
conv k w (VSPair u v) =
conv k (fstSVal w) u <&&> conv k (sndSVal w) v
conv k (VApp u v) (VApp u' v') = conv k u u' <&&> conv k v v'
conv k (VAppName u x) (VAppName u' x') = conv k u u' <&&> (x <==> x')
conv k (VSplit u v) (VSplit u' v') = conv k u u' <&&> conv k v v'
conv k (VVar x d) (VVar x' d') = return $ (x == x') && (d == d')
conv k (VInhRec b p phi v) (VInhRec b' p' phi' v') =
andM [conv k b b', conv k p p', conv k phi phi', conv k v v']
conv k VCircle VCircle = return True
conv k VBase VBase = return True
conv k (VLoop x) (VLoop y) = x <==> y
conv k (VCircleRec f b l v) (VCircleRec f' b' l' v') =
andM [conv k f f', conv k b b', conv k l l', conv k v v']
conv k VI VI = return True
conv k VI0 VI0 = return True
conv k VI1 VI1 = return True
conv k (VLine x) (VLine y) = x <==> y
conv k (VIntRec f s e l u) (VIntRec f' s' e' l' u') =
andM [conv k f f', conv k s s', conv k e e', conv k l l', conv k u u']
conv k _ _ = return False
-- Monadic version of conv
convM :: Int -> Eval Val -> Eval Val -> Eval Bool
convM k v1 v2 = do
v1' <- v1
v2' <- v2
conv k v1' v2'
convBox :: Int -> Box Val -> Box Val -> Eval Bool
convBox k box@(Box d pn _ ss) box'@(Box d' pn' _ ss') =
if (d == d') && (pn == pn') && (sort np == sort np')
then and <$> sequence [ conv k (lookBox s box) (lookBox s box')
| s <- defBox box ]
else return False
where (np, np') = (nonPrincipal box, nonPrincipal box')
convEnv :: Int -> OEnv -> OEnv -> Eval Bool
convEnv k e e' = liftM and $ zipWithM (conv k) (valOfOEnv e) (valOfOEnv e')