uAgda-1.2.0.1: Normal.hs
{-# LANGUAGE GADTs, KindSignatures, OverloadedStrings, EmptyDataDecls, StandaloneDeriving, TypeSynonymInstances, TypeFamilies, MultiParamTypeClasses, ViewPatterns, RankNTypes #-}
module Normal where
import Prelude hiding (length,elem,foldl)
import Basics
import Display
import Data.Foldable
import Control.Arrow (first, second)
import Data.Sequence hiding (zip,replicate,reverse)
import Options
import qualified Data.List as L
import Permutation
data No
data Ne
data Va
type NF = Term No
type Neutral = Term Ne
type Variable = Term Va
type NF' = (NF, NF) -- value, type.
data Role = Index | Thing deriving (Eq, Show)
showRole Index = "?"
showRole Thing = "!"
data Term n :: * where
Neu :: Neutral -> NF
Var :: Variable -> Neutral
Star :: Sort -> NF
Pi :: Binder -> Ident -> Cube NF -> NF -> NF
Lam :: Binder -> Ident -> Cube NF -> NF -> NF
App :: Binder -> Neutral -> Cube NF -> Neutral -- The sort is that of the argument.
Sigma :: Binder -> Ident -> NF -> NF -> NF
Pair :: Binder -> Ident -> NF -> NF -> NF -- Pair does not bind any variable.
Proj :: Binder -> -- ^ Sort of the argument (only needed for
-- the 1st projection: 2nd projection does
-- not change relevance)
Neutral -> Bool -> -- ^ True for 1st projection; False for 2nd.
Ident -> Neutral
-- OfParam :: Ident -> NF -> Neutral
-- Destr :: Int -> Variable -> Variable -- argument: depth where destruction occurs.
Swap :: Permutation -> Variable -> Variable
Param :: Role {-TODO: Maybe the swap should be merged into the role -} -> Variable -> Variable
V :: BitVector -> Int -> Variable -- shift, deBruijn
Hole :: Irr String -> Variable
type Subst = [Cube NF]
deriving instance Eq (Term n)
deriving instance Show (Term n)
var :: Int -> NF
var x = Neu $ var' x
var'' = V nil
var' x = Var $ V nil x
-- | Hereditary substitution
subst0 :: Cube NF -> NF -> NF
subst0 u = subst (u:map (unit . var) [0..])
hole = Neu . Var . Hole . Irr
subst :: Subst -> Term n -> NF
subst f t = case t of
Neu x -> s x
Var x -> s x
Star x -> Star x
Lam o i ty bo -> Lam o i (fmap s ty) (s' bo)
(Pair o i x y) -> Pair o i (s x) (s y)
Pi o i a b -> Pi o i (fmap s a) (s' b)
Sigma o i a b -> Sigma o i (s a) (s' b)
(App o a b) -> app o (s a) (fmap s b)
(Proj o x k f) -> proj o (s x) k f
-- OfParam i x -> Neu (OfParam i (s x))
-- Destr d x -> destroy d (s x)
Hole (Irr x) -> hole x
V bv x -> let fx = f!!x in
case cubeElems fx of
[Neu (Var (V bv' y))] -> Neu $ Var $ V (bv' <> bv) y
_ | dim (f !! x) /= bvDim bv -> hole $ "error: variable access dim " ++ show (bvDim bv) ++ " expected " ++ show (dim (f!!x))
_ -> (f !! x) !? bv
Param r x -> param r (s x)
Swap q x -> swap q (s x)
where s,s' :: forall n. Term n -> NF
s' = subst (unit (var 0) : map (cmap wk) f)
s = subst f
both f (x,y) = (f x, f y)
-----------------------------
-- Hereditary operations
app :: Binder -> NF -> Cube NF -> NF
app Pred x u | dim u == 0 = x
app _ (Lam _ i _ bo) u = subst0 u bo
app o (Neu n) u = Neu (App o n u)
-- TODO: merge App Pred's
proj :: Binder -> NF -> Bool -> Ident -> NF
proj _ (Pair _ _ x y) True f = x
proj _ (Pair _ _ x y) False f = y
proj o (Neu x) k f = Neu (Proj o x k f)
wkn :: Int -> NF -> NF
wkn = wkdn 0
wkdn :: Int -> Int -> NF -> NF
wkdn d n = subst (map (unit . var) [0..d-1] ++ map (unit . var) [d+n..])
wk = wkn 1
str = strn 1
strn n = subst (replicate n (unit $ hole "str: oops!") ++ map (unit . var) [0..])
wkv :: Int -> Variable -> Variable
wkv n (Param r x) = Param r (wkv n x)
wkv n (Swap q x) = Swap q (wkv n x)
wkv n (V s x) = V s (x + n)
wkv n (Hole x) = Hole x
param :: Role -> NF -> NF
param r = transNF r noAction
-----------------------------------
-- Display
dec xs = [ x - 1 | x <- xs, x > 0]
allFreeVars :: Cube (Term n) -> [Int]
allFreeVars = L.concat . fmap freeVars . cubeElems
freeVars :: Term n -> [Int]
freeVars (Var x) = freeVars x
--freeVars (Destr _ x) = freeVars x
freeVars (Neu x) = freeVars x
freeVars (Pi _ _ a b) = allFreeVars a <> (dec $ freeVars b)
freeVars (Sigma _ _ a b) = freeVars a <> (dec $ freeVars b)
freeVars (V _ x) = [x]
freeVars (App _ a b) = freeVars a <> allFreeVars b
freeVars (Lam _ _ ty b) = allFreeVars ty <> (dec $ freeVars b)
freeVars (Star _) = mempty
freeVars (Hole _) = mempty
freeVars (Pair _ _ x y) = freeVars x <> freeVars y
freeVars (Proj _ x _ _) = freeVars x
freeVars (Param _ x) = freeVars x
freeVars (Swap _ x) = freeVars x
-- freeVars (OfParam _ x) = freeVars x
iOccursIn :: Int -> Term n -> Bool
iOccursIn x t = x `elem` (freeVars t)
allocName :: DisplayContext -> Ident -> Ident
allocName g s
| fromIrr s `elem` (fmap fromIrr g) = allocName g (modId (++ "'") s)
| otherwise = s
printIndex :: DisplayContext -> Int -> Doc
printIndex ii k
| k < 0 || k >= length ii = text "<deBrujn index" <+> pretty k <+> text "out of range>"
| otherwise = pretty (ii `index` k)
cPrint :: Int -> DisplayContext -> Term n -> Doc
cPrint p ii (Swap q x) = cPrint p ii x <> "#" <> pretty q
cPrint p ii (Var x) = cPrint p ii x
cPrint p ii (Neu x) = cPrint p ii x
cPrint p ii (Param r x) = cPrint p ii x <> text (showRole r)
-- cPrint p ii (Destr d x) = cPrint p ii x <> "%" <> pretty d
-- cPrint p ii (OfParam i x) = pretty i
-- "⌊" <> cPrint (-1) ii x <> "⌋"
cPrint p ii (Hole (Irr x)) = text x
cPrint p ii (Star i) = pretty i
cPrint p ii (V bv k) = printIndex ii k <> (mconcat $ map subscriptPretty $ map b2i $ bits bv)
cPrint p ii (Proj o x k (Irr f)) = cPrint p ii x <> (if k then "." <> pretty f else "/")
cPrint p ii t@(App _ _ _) = parensIf (p > 3) (cPrint 3 ii fct <+> sep [appl o <> printCube o 4 ii a | (o,a) <- args])
where (fct,args) = nestedApp t
cPrint p ii t@(Pi _ _ _ _) = parensIf (p > 1) (printBinders arrow ii mempty $ nestedPis t)
cPrint p ii t@(Sigma _ _ _ _) = parensIf (p > 1) (printBinders cross ii mempty $ nestedSigmas t)
cPrint p ii (t@(Lam _ _ _ _)) = parensIf (p > 1) (nestedLams ii mempty t)
cPrint p ii (Pair o name x y) = parensIf (p > (-1)) (sep [pretty name <+> text "=" <+> cPrint 0 ii x <> comm o,
cPrint (-1) ii y])
nestedPis :: NF -> ([(Ident,Bool,Cube NF,Binder)], NF)
nestedPis (Pi o i a b) = (first ([(i,0 `iOccursIn` b,a,o)] ++)) (nestedPis b)
nestedPis x = ([],x)
nestedSigmas :: NF -> ([(Ident,Bool,Cube NF,Binder)], NF)
nestedSigmas (Sigma o i a b) = (first ([(i,0 `iOccursIn` b,unit a,o)] ++)) (nestedSigmas b)
nestedSigmas x = ([],x)
printBinders :: (Binder -> Doc) -> DisplayContext -> Seq Doc -> ([(Ident,Bool,Cube NF,Binder)], NF) -> Doc
printBinders sep ii xs (((x,occurs,a,o):pis),b) = printBinders sep (i <| ii) (xs |> (printBind' ii i occurs a o <+> sep o)) (pis,b)
where i = allocName ii x
printBinders _ ii xs ([],b) = sep $ toList $ (xs |> cPrint 1 ii b)
nestedLams :: DisplayContext -> Seq Doc -> Term n -> Doc
nestedLams ii xs (Lam o x ty c) = nestedLams (i <| ii) (xs |> parens (pretty i <+> colon o <+> printCube o 0 ii ty)) c
where i = allocName ii x
nestedLams ii xs t = (text "\\ " <> (sep $ toList $ (xs |> "->")) <+> nest 3 (cPrint 0 ii t))
printCube :: Binder -> Int -> DisplayContext -> Cube (Term n) -> Doc
printCube o p ii d | dim d == 0 = cPrint p ii (d !? nil)
| otherwise = "{" <> sep (punctuate ";" [(if showIndices options then pretty i <> "↦" else mempty ) <>
cPrint 0 ii x | (i,x) <- adjust $ cubeAssocs d]) <> "}"
where adjust = case o of
Pred -> init
Regu -> id
printBind' ii name occurs d o = case not (isDummyId name) || occurs of
True -> parens $ pretty name <+> colon o <+> printCube o 0 ii d
False -> printCube o 2 ii d
nestedApp :: Neutral -> (Neutral,[(Binder, Cube NF)])
nestedApp (App o f a) = (second (++ [(o,a)])) (nestedApp f)
nestedApp t = (t,[])
prettyTerm = cPrint (-100)
instance Pretty (Term n) where
pretty = prettyTerm mempty
type Action = [(NF,NF)] -- TODO: use Seq
paramv :: BitVector -> Role -> Int -> NF
paramv bv Thing x = Neu $ Var $ Param Thing $ V bv x
paramv bv Index x = Neu $ Var $ V bv x
noAction = []
wka = map (both wk)
addAct1 as = (Neu $ Var $ V (zeros 1) 0, Neu $ Var $ V (ones 1) 0) : wka as
addAct2 as = error "accessing crap" : wka as
recVarName = synthId "°"
scopeCheck c k | 0 `iOccursIn` c = error "swapTy: improperly scoped Sigma"
| otherwise = c
swap q = swapNF q 0
swapV :: Permutation -> Variable -> Variable
swapV q x | isIdentity q = x
swapV q (V bv x) = Swap q $ V bv x
swapV q (Swap q' v) = swapV (q `after` q') v
swapV q v@(Param _ _) | isIdentity q' = v
| otherwise = Swap (simplifyPerm n q) v
where n = countParam v
q' = simplifyPerm n q
swapV q (Hole (Irr s)) = Hole $ Irr (s ++ "#")
swapV q x = Swap q x
-- FIXME: what about the role=Index? There should not be a (Param Index) in the syntax.
countParam (Param Thing x) = 1 + countParam x
countParam x = 0
fullVarCube x = full (\i -> Neu $ Var $ V i x)
swapSubst :: Permutation -> NF -> NF
swapSubst q = subst $ (apply (invert q) $ fullVarCube 0 $ permLength q) : map (unit . var) [1..]
swapNe :: Permutation -> Int -> Neutral -> Neutral
swapNe q d (Var v) = Var $ swapV q v
swapNe q d (App o f a) = App o (swapNe q d f) (swapCube q d a)
swapNe q d (Proj o x k f) = Proj o (swapNe q d x) k f
swapCube :: Permutation -> Int -> Cube NF -> Cube NF
swapCube q0 d c = apply q . subAppl q (\p -> swapNF p d) $ c
where q = reducePerm q0 (dim c) -- FIXME: reduction should never be necessary
swapBinder :: Permutation -> Int -> Cube NF -> Cube NF
swapBinder = swapCube
swapNF :: Permutation -> Int -> NF -> NF
swapNF q d (Neu v) = Neu $ swapNe q d v
swapNF q d (Star x) = Star x
-- swapNF q d (Pair o i a b) = Pair o i (swapBinder q d a) (swapNF q d b)
swapNF q d (Lam o i a b) = Lam o i (swapBinder q d a) (swapSubst q $ swapNF q (d+1) b)
swapNF q d (Pi o i a b) = Pi o i (swapBinder q d a) (swapSubst q $ swapNF q (d+1) b)
-- swapNF q d (Sigma o i a b) = Sigma o i (swapBinder q d a) (swapNF q (d+1) b)
getVar :: Variable -> Int
getVar (Param _ x) = getVar x
getVar (V _ x) = x
getVar (Hole x) = (-1)
getVar (Swap _ x) = getVar x
getDepth :: Variable -> Int
getDepth (Param _ x) = 1 + getDepth x
getDepth (V _ x) = 0
getDepth (Hole x) = 0
getDepth (Swap _ x) = getDepth x
-- | Transform a term to its relational interpretation
transV :: Role -> Action -> Variable -> NF
transV Thing d (Swap q x) = swap (extendPerm q) $ transV Thing d x
transV Index d (Swap q x) = swap q $ transV Index d x
transV r d (V bv x) | x < L.length d = Neu $ Var $ case r of Thing -> V (bv <> ones 1) x; Index -> V (bv <> zeros 1) x
| otherwise = paramv bv r x
-- transV r [] (Param r' x) = Neu $ Var $ Param r $ Param r' x
transV r d (Param r' x)
| getVar x < L.length d = maybeSwap $ param r' $ transV r d x -- the inner variable is known; go through
| otherwise = Neu $ Var $ maybeParam $ Param r' x -- the inner variable is not known ~> stop here and forget about other variables
where maybeSwap = if r == Thing then swap (swap2 (n+2) (n+1) n) else id -- add a swap if we are doing "proper" parametricity
maybeParam = if r == Thing then Param r else id -- keep only "proper" parametricity
n = getDepth x
transV r d (Hole (Irr s)) = hole (s ++ showRole r)
transNe :: Role -> Action -> Neutral -> NF
transNe r d (Var v) = transV r d v
transNe Thing d (App o f a) = app o (transNe Thing d f) (extend d a)
transNe Index d (App o f a) = app o (transNe Index d f) (cmap (transNF Index d) a)
transNe r d (Proj o x k f) = proj o (transNe r d x) k f
isLam :: Term n -> Bool
isLam (Lam _ _ _ _) = True
isLam _ = False
transNF :: Role -> Action -> NF -> NF
transNF r d (Neu v) = transNe r d v
transNF r d p@(Lam Pred i ty bo) = Lam Pred i (updateCube ix p $ extend d ty) (inTrans (addAct1 d) bo (Neu $ Var $ V ix 0))
where ix = ones (dim ty) <> zeros 1
transNF r d (Lam o i ty bo) = Lam o i (extend d ty) (transNF r (addAct1 d) bo)
transNF r d (Pair o i x y) = Pair o i (transNF r d x) (transNF r d y)
transNF Index d (Star x) = Star x
transNF Index d (Pi o i a b) = Pi o i (cmap (transNF Index d) a) (transNF Index d b)
transNF Index d (Sigma o i a b) = Sigma o i ((transNF Index d) a) (transNF Index d b)
transNF r d ty@(Star _) = trans' r d ty
transNF r d ty@(Pi _ _ _ _) = trans' r d ty
transNF r d ty@(Sigma _ _ _ _) = trans' r d ty
extend d a = cubeCons (cmap (transNF Index d) a) (cmap (transNF Thing d) a)
trans' :: Role -> Action -> NF -> NF
trans' Index d ty = error $ "trans': Index: wrong arg: " ++ show ty
trans' Thing d ty = Lam Pred (synthId "z") (unit1 (transNF Index d ty)) (zerInRel d ty)
-- | Build the relation x ∈ ⟦ty⟧. (where 'x' is 0; but not bound in 'ty'.)
zerInRel :: Action -> NF -> NF
zerInRel d ty = inTrans (addAct2 d) (wk ty) (Neu $ Var $ V (zeros 1) 0)
-- | Build a relation z ∈ ⟦ty⟧. z is a term that, after renaming,
-- gives the vector of terms member of the relation. Note that
-- 'trans' is never applied to 'z', therefore 'zR' never occurs in the result.
inTrans :: Action -> NF -> NF -> NF
inTrans d (Neu (App Pred f a)) z = app Pred (transNe Thing d f) (updateCube (ones (dim a) <> zeros 1) z (extend d a))
inTrans d (Star (Sort l δ)) z = (Pi Pred dummyId (unit1 z) (Star $ Sort l (δ+1)))
inTrans d (Pi Pred i a (Star (Sort l δ))) z = Pi Pred i (updateCube (ones (dim a) <> zeros 1) z (extend d a)) (Star $ Sort l (δ+1))
inTrans d (Pi o i a b) z = Pi o i (extend d a) (inTrans (addAct1 d) b (app o (wk z) (unit $ transNF Index (addAct1 d) $ var 0)))
inTrans d (Sigma o i a b) z = Sigma o i (inTrans d a (proj o z True i))
(inTrans ((wk $ proj o z True i,var 0):wka d) b (proj o (wk z) False i))
inTrans d ty z = app Pred (transNF Thing d ty) (unit1 z)
unit1 z = (pair z (hole "⊘"))