Skip to content

Instantly share code, notes, and snippets.

@cheery
Last active February 11, 2022 16:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cheery/1663bd6574754dbdc7a546d67b80b902 to your computer and use it in GitHub Desktop.
Save cheery/1663bd6574754dbdc7a546d67b80b902 to your computer and use it in GitHub Desktop.
module SimplyEasy where
-- From the paper: http://strictlypositive.org/Easy.pdf
-- An attempt to add case -statement.
-- Fails on typechecking a case.
data Name
= Const String
| Bound Int
| Unquoted Int
deriving (Show, Eq)
data TermNe
= Ann TermN TermN
| Star
| Pi TermN TermN
| Var Int
| Par Name
| TermNe :@: TermN
-- | Nat
-- | NatElim TermN TermN TermN TermN
-- | Vec TermN TermN
-- | VecElim TermN TermN TermN TermN TermN TermN
| Spec
| Data TermN [TermN]
| Case TermN TermNe [TermN]
-- | Des TermN String [TermN]
-- | Field TermNe Int
deriving (Show, Eq)
data TermN
= Inf TermNe
| Lam TermN
-- | Zero
-- | Succ TermN
-- | Nil TermN
-- | Cons TermN TermN TermN TermN
--
-- | Record [TermN]
-- | Cocase [(String, TermN)]
| Con Int [TermN]
-- | CSpec [TermN] [(String, ([TermN], [TermN], TermN))]
| DSpec [TermN] [[TermN]]
-- | RSpec [TermN] [TermN]
deriving (Show, Eq)
------------------------------------------------------------
-- Evaluator
------------------------------------------------------------
type Env = [Value]
evalNe :: TermNe -> Env -> Value
evalNe (Ann e _) d = evalN e d
evalNe Star d = VStar
evalNe (Pi t t') d = VPi (evalN t d) (\x -> evalN t' (x : d))
evalNe (Par x) d = vpar x
evalNe (Var i) d = d !! i
evalNe (e1 :@: e2) d = vapp (evalNe e1 d) (evalN e2 d)
evalNe Spec d = VSpec
evalNe (Case m n cs) d
= let nVal = evalNe n d in
case nVal of
VCon i args -> foldl vapp (evalN (cs !! i) d) args
VNeutral n -> VNeutral
(NCase (evalN m d) n (map (\c -> evalN c d) cs))
_ -> error "runtime type error"
evalNe (Data s h) d = VData (evalN s d) (map (\x -> evalN x d) h)
-- evalNe Nat d = VNat
-- evalNe (NatElim m mz ms n) d
-- = let mzVal = evalN mz d
-- msVal = evalN ms d
-- rec nVal =
-- case nVal of
-- VZero -> mzVal
-- VSucc k -> msVal `vapp` k `vapp` rec k
-- VNeutral n -> VNeutral
-- (NNatElim (evalN m d) mzVal msVal n)
-- _ -> error "runtime type error"
-- in rec (evalN n d)
-- evalNe (VecElim a m mn mc n xs) d
-- = let mnVal = evalN mn d
-- mcVal = evalN mc d
-- rec nVal xsVal = case xsVal of
-- VNil _ -> mnVal
-- VCons _ k x xs -> foldl vapp mcVal [k, x, xs, rec k xs]
-- VNeutral n -> VNeutral
-- (NVecElim (evalN a d) (evalN m d)
-- mnVal mcVal nVal n)
-- _ -> error "runtime type error"
-- in rec (evalN n d) (evalN xs d)
-- evalNe (Vec a n) d = VVec (evalN a d) (evalN n d)
-- evalNe (Data args) d = VNeutral (NData (evalN args d))
vapp :: Value -> Value -> Value
vapp (VLam f) v = f v
vapp (VNeutral n) v = VNeutral (NApp n v)
vapp _ v = error "runtime type error"
evalN :: TermN -> Env -> Value
evalN (Inf i) d = evalNe i d
evalN (Lam e) d = VLam (\x -> evalN e (x : d))
evalN (Con k xs) d = VCon k (map (\x -> evalN x d) xs)
evalN (DSpec h xxs) d = VDSpec (map (\x -> evalN x d) h)
(map (map (\x -> evalN x d)) xxs)
-- evalN Zero d = VZero
-- evalN (Succ k) d = VSucc (evalN k d)
-- evalN (Nil a) d = VNil (evalN a d)
-- evalN (Cons a n x xs) d = VCons (evalN a d) (evalN n d) (evalN x d) (evalN xs d)
data Value
= VLam (Value -> Value)
| VStar
| VPi Value (Value -> Value)
| VNeutral Neutral
| VCon Int [Value]
| VDSpec [Value] [[Value]]
| VData Value [Value]
-- | VNat
-- | VZero
-- | VSucc Value
-- | VNil Value
-- | VCons Value Value Value Value
-- | VVec Value Value
--
| VSpec
-- | VData Value [Value]
-- | VDSpec [Value] [(String, ([Value], [Value]))]
data Neutral
= NPar Name
| NApp Neutral Value
| NCase Value Neutral [Value]
-- | NNatElim Value Value Value Neutral
-- | NVecElim Value Value Value Value Value Neutral
vpar :: Name -> Value
vpar n = VNeutral (NPar n)
------------------------------------------------------------
-- Contexts
------------------------------------------------------------
type Type = Value
type Context = [(Name, Type)]
infer0 :: Context -> TermNe -> Result Type
infer0 = infer 0
infer :: Int -> Context -> TermNe -> Result Type
infer i g (Ann e t)
= do check i g t VStar
let v = evalN t []
check i g e v
return v
infer i g Star
= return VStar
infer i g (Pi t t')
= do check i g t VStar
let v = evalN t' []
check (i + 1) ((Bound i, v) : g)
(substN 0 (Par (Bound i)) t') VStar
return VStar
infer i g (Var x) = error "impossible"
infer i g (Par x)
= case lookup x g of
Just v -> return v
Nothing -> throwError "unknown identifier"
infer i g (e1 :@: e2)
= do o <- infer i g e1
case o of
VPi t f -> do check i g e2 t
return (f (evalN e2 []))
_ -> throwError "illegal application"
infer i g Spec = return VStar
infer i g (Data spec params) = do
check i g spec VSpec
head <- getSpecHead spec
checkParams i g params (map (\e -> evalN e []) head) (buildTail head id)
pure VStar
-- Now the case statement is not going through.
-- infer i g (Case rtype arg cases) = do
-- check i g restype VStar
-- let rVal = evalN restype []
-- t <- infer i g arg
-- (VData (VDSpec _ ss) args) -> do
-- mapM (checkCase ss args rVal) cases
-- _ -> throwError "type mismatch"
getSpecHead :: TermN -> Result [TermN]
-- getSpecHead (CSpec a _) = pure a
getSpecHead (DSpec a _) = pure a
-- getSpecHead (RSpec a _) = pure a
getSpecHead _ = throwError "not a spec"
--
-- checkCase :: [(String, ([Value], [Value]))]
-- -> [Value]
-- -> Value
-- -> (String, TermN)
-- -> Either String ()
-- checkCase ss args restype (s, term) = throwError "TODO"
-- infer i g Nat = return VStar
-- infer i g (NatElim m mz ms n) =
-- do check i g m (VPi VNat (const VStar))
-- let mVal = evalN m []
-- check i g mz (mVal `vapp` VZero)
-- check i g ms
-- (VPi VNat (\n ->
-- VPi (mVal `vapp` n) (\_ -> mVal `vapp` VSucc n)))
-- check i g n VNat
-- let nVal = evalN n []
-- return (mVal `vapp` nVal)
-- infer i g (Vec a n)
-- = do check i g a VStar
-- check i g n VNat
-- return VStar
-- infer i g (VecElim a m mn mc n vs)
-- = do check i g a VStar
-- let aVal = evalN a []
-- check i g m
-- (VPi VNat (\n -> (VPi (VVec aVal n) (\_ -> VStar))))
-- let mVal = evalN m []
-- check i g mn (foldl vapp mVal [VZero, VNil aVal])
-- check i g mc
-- (VPi VNat (\n ->
-- (VPi aVal (\y ->
-- (VPi (VVec aVal n) (\ys ->
-- (VPi (foldl vapp mVal [n, ys]) (\_ ->
-- (foldl vapp mVal [VSucc n, VCons aVal n y ys])))))))))
-- check i g n VNat
-- let nVal = evalN n []
-- check i g vs (VVec aVal nVal)
-- let vsVal = evalN vs []
-- return (foldl vapp mVal [nVal, vsVal])
check :: Int -> Context -> TermN -> Type -> Result ()
check i g (Inf e) t
= do t' <- infer i g e
checkEq t t' "type mismatch"
check i g (Lam e) (VPi v f)
= check (i + 1) ((Bound i, v) : g)
(substN 0 (Par (Bound i)) e) (f (vpar (Bound i)))
check i g (Con k xs) (VData (VDSpec _ xxs) zs) = do
let f = buildAp zs id
checkParams i g xs (xxs !! k) f
check i g (DSpec h xs) VSpec = do
tys' <- checkXs i g h []
mapM_ (\ys -> checkXs i g ys tys') xs
check i g _ _
= throwError "type mismatch"
checkXs i g [] tys = pure tys
checkXs i g (x:xs) tys = do
check i g x (buildTy tys VStar)
let tys' = (evalN x []) : tys
checkXs i g xs tys'
buildTy [] ty = ty
buildTy (x:xs) ty = buildTy xs (VPi x (const ty))
buildAp :: [Value] -> (Value -> Value) -> (Value -> Value)
buildAp [] f = f
buildAp (h:hs) f = buildAp hs (\a -> f a `vapp` h)
-- check i g Zero VNat = return ()
-- check i g (Succ k) VNat = check i g k VNat
-- check i g (Nil a) (VVec bVal VZero)
-- = do check i g a VStar
-- let aVal = evalN a []
-- checkEq aVal bVal "type mismatch"
-- check i g (Cons a n x xs) (VVec bVal (VSucc k))
-- = do check i g a VStar
-- let aVal = evalN a []
-- checkEq aVal bVal "type mismatch"
-- check i g n VNat
-- let nVal = evalN n []
-- checkEq nVal k "number mismatch"
-- check i g x aVal
-- check i g xs (VVec bVal k)
checkEq :: Value -> Value -> String -> Result ()
checkEq t t' s = if (quote0 t == quote0 t')
then return ()
else (throwError s)
buildTail :: [TermN] -> (Value -> Value) -> Value -> Value
buildTail [] f = f
buildTail (x:xs) f = buildTail xs (\a -> vapp (f a) (evalN x []))
checkParams :: Int -> Context -> [TermN] -> [Type] -> (Type -> Type) -> Either String ()
checkParams i g [] [] f = pure ()
checkParams i g (x:xs) (t:ts) f = do
check i g x (f t)
checkParams i g xs ts (\a -> vapp (f a) (evalN x []))
checkParams i g _ _ f = throwError "mismatching argc"
type Result a = Either String a
throwError :: String -> Result a
throwError = Left
substNe :: Int -> TermNe -> TermNe -> TermNe
substNe i r (Ann e t) = Ann (substN i r e) t
substNe i r Star = Star
substNe i r (Pi t t') = Pi (substN i r t) (substN (i + 1) r t')
substNe i r (Var j) = if i == j then r else Var j
substNe i r (Par y) = Par y
substNe i r (e1 :@: e2) = substNe i r e1 :@: substN i r e2
substNe i r Spec = Spec
substNe i r (Case a x xs) = Case (substN i r a) (substNe i r x) (substMany i r xs)
substNe i r (Data h xs) = Data (substN i r h) (map (substN i r) xs)
-- substNe i r (Data spec parms) = Data (substN i r spec) (map (substN i r) parms)
-- substNe i r (Case rv arg fd) = Case (substN i r rv) (substNe i r arg)
-- (map (\(s,x) -> (s, substN i r x)) fd)
-- substNe i r (Des spec s a) = Des (substN i r spec) s (map (substN i r) a)
-- substNe i r (Field a k) = Field (substNe i r a) k
-- substNe i r Nat = Nat
-- substNe i r (NatElim m mz ms n) = NatElim
-- (substN i r m)
-- (substN i r mz)
-- (substN i r ms)
-- (substN i r n)
-- substNe i r (Vec a n) = Vec
-- (substN i r a)
-- (substN i r n)
-- substNe i r (VecElim a m mn mc n xs) = VecElim
-- (substN i r a)
-- (substN i r m)
-- (substN i r mn)
-- (substN i r mc)
-- (substN i r n)
-- (substN i r xs)
substN :: Int -> TermNe -> TermN -> TermN
substN i r (Inf e) = Inf (substNe i r e)
substN i r (Lam e) = Lam (substN (i + 1) r e)
-- substN i r (Record p) = Record (map (substN i r) p)
-- substN i r (Cocase c) = Cocase (map (\(s,x) -> (s, substN i r x)) c)
-- substN i r (Con spec n f) = Con (substN i r spec) n (map (substN i r) f)
-- substN i r (CSpec p dt) = CSpec (map (substN i r) p) (map (substCRow i r) dt)
substN i r (Con k x) = Con k (map (substN i r) x)
substN i r (DSpec p dt) = DSpec (map (substN i r) p) (map (substMany i r) dt)
-- substN i r (RSpec p ds) = RSpec (map (substN i r) p) (map (substN i r) ds)
-- substCRow :: Int
-- -> TermNe
-- -> (String, ([TermN], [TermN], TermN))
-- -> (String, ([TermN], [TermN], TermN))
-- substCRow i r (s, (a, p, q)) = (s,
-- (map (substN i r) a,
-- map (substN i r) p,
-- substN i r q))
substMany :: Int -> TermNe -> [TermN] -> [TermN]
substMany i r xs = map (substN i r) xs
--
-- substDRow :: Int
-- -> TermNe
-- -> (String, ([TermN], [TermN]))
-- -> (String, ([TermN], [TermN]))
-- substDRow i r (s, (a, p)) = (s, (map (substN i r) a,
-- map (substN i r) p))
-- substN i r Zero = Zero
-- substN i r (Succ k) = Succ (substN i r k)
-- substN i r (Nil a) = Nil (substN i r a)
-- substN i r (Cons a n x xs) = Cons (substN i r a)
-- (substN i r n)
-- (substN i r x)
-- (substN i r xs)
------------------------------------------------------------
-- Quotation
------------------------------------------------------------
quote0 :: Value -> TermN
quote0 = quote 0
quote :: Int -> Value -> TermN
quote i (VLam f) = Lam (quote (i + 1) (f (vpar (Unquoted i))))
quote i (VNeutral n) = Inf (neutralQuote i n)
quote i VStar = Inf Star
quote i (VPi v f)
= Inf (Pi (quote i v) (quote (i + 1) (f (vpar (Unquoted i)))))
quote i VSpec = Inf Spec
quote i (VCon k xs) = Con k (map (quote i) xs)
quote i (VDSpec h xs) = DSpec (map (quote i) h) (map (map (quote i)) xs)
quote i (VData h xs) = Inf (Data (quote i h) (map (quote i) xs))
-- quote i VNat = Inf Nat
-- quote i VZero = Zero
-- quote i (VSucc k) = Succ (quote i k)
-- quote i (VNil n) = Nil (quote i n)
-- quote i (VCons a n x xs) = Cons (quote i a) (quote i n) (quote i x) (quote i xs)
-- quote i (VVec a n) = Inf (Vec (quote i a) (quote i n))
neutralQuote :: Int -> Neutral -> TermNe
neutralQuote i (NPar x) = varpar i x
neutralQuote i (NApp n v) = neutralQuote i n :@: quote i v
neutralQuote i (NCase a x xs) = Case (quote i a) (neutralQuote i x)
(map (quote i) xs)
-- neutralQuote i (NNatElim m mz ms n) = NatElim
-- (quote i m)
-- (quote i mz)
-- (quote i ms)
-- (Inf (neutralQuote i n))
-- neutralQuote i (NVecElim a m mn mc n xs) = VecElim
-- (quote i a)
-- (quote i m)
-- (quote i mn)
-- (quote i mc)
-- (quote i n)
-- (Inf (neutralQuote i xs))
varpar :: Int -> Name -> TermNe
varpar i (Unquoted k) = Var (i - k - 1)
varpar i x = Par x
-- id' = Lam (Inf (Var 0))
-- const' = Lam (Lam (Inf (Var 1)))
par a = Par (Const a)
-- par x = Inf (Par (Const x))
-- term1 = Ann id' (Fun (tpar "a") (tpar "a")) :@: par "y"
-- term2 = Ann const' (Fun (Fun (tpar "b") (tpar "b"))
-- (Fun (tpar "a")
-- (Fun (tpar "b") (tpar "b"))))
-- :@: id' :@: par "y"
-- env1 = [(Const "y", HasType (tpar "a")),
-- (Const "a", HasKind Star)]
-- env2 = [(Const "b", HasKind Star)] ++ env1
test = do
let id' = (Lam (Inf (Var 0))) `Ann` Inf (Pi (Inf (par "a")) (Inf (par "a")))
print id'
print "hello"
let result = (infer0 [(Const "a", VStar)] id') >>= pure . quote0
print result
--print (check 0 [] id' (Pi (Par (Const "a")) (Par (Const "a"))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment