on master help sign in
Tactics can now complete basic proofs
commitbb6bba29b4518376e584a10a3f90f419cfb40063 authorEdwin Brady <eb@cs.st-andrews.ac.uk> dateFri 23 Sep 2011, 01:56 (15 years ago) parent6923ac1
5 files changed+201−80
src/Core.hs+71−21 src/ProofShell.hs+16−3 src/ProofState.hs+102−50 src/ShellParser.hs+10−5 src/Typecheck.hs+2−1
src/Core.hs+71−21
@@ -87,28 +87,74 @@ type Type = Term
8787
8888type Env = EnvTT Name
8989
90+-- an environment with de Bruijn indices 'normalised' so that they all refer to
91+-- this environment
92+
93+newtype WkEnvTT n = Wk (EnvTT n)
94+type WkEnv = WkEnvTT Name
95+
9096instance Show n => Show (TT n) where
91− show t = se 10 [] t where
92− se p env (P _ n _) = show n
93− se p env (V i) | i < length env = show $ fst $ env!!i
94− | otherwise = "!!V " ++ show i ++ "!!"
95− se p env (Bind n b sc) = bracket p 2 $ sb env n b ++ se 10 ((n,b):env) sc
96− se p env (App f t a) = bracket p 1 $ se 1 env f ++ " " ++ se 0 env a
97− se p env (Set i) = "Set" ++ show i
98−
99− sb env n (Lam t) = showb env "\\ " " => " n t
100− sb env n (Hole t) = showb env "? " ". " n t
101− sb env n (Pi t) = showb env "forall " " -> " n t
102− sb env n (PVar t) = showb env "! " ". " n t
103− sb env n (Let t v) = showbv env "let " " in " n t v
104− sb env n (Guess t v) = showbv env "?? " " in " n t v
105−
106− showb env op sc n t = op ++ show n ++ " : " ++ se 10 env t ++ sc
107− showbv env op sc n t v = op ++ show n ++ " : " ++ se 10 env t ++ " = " ++
108− se 10 env v ++ sc
109−
110− bracket outer inner str | inner > outer = "(" ++ str ++ ")"
111− | otherwise = str
97+ show t = showEnv [] t
98+
99+showEnv env t = showEnv' env t False
100+showEnvDbg env t = showEnv' env t True
101+
102+showEnv' env t dbg = se 10 env t where
103+ se p env (P _ n _) = show n
104+ se p env (V i) | i < length env = (show $ fst $ env!!i) ++
105+ if dbg then "{" ++ show i ++ "}" else ""
106+ | otherwise = "!!V " ++ show i ++ "!!"
107+ se p env (Bind n b sc) = bracket p 2 $ sb env n b ++ se 10 ((n,b):env) sc
108+ se p env (App f t a) = bracket p 1 $ se 1 env f ++ " " ++ se 0 env a
109+ se p env (Set i) = "Set" ++ show i
110+
111+ sb env n (Lam t) = showb env "\\ " " => " n t
112+ sb env n (Hole t) = showb env "? " ". " n t
113+ sb env n (Pi t) = showb env "forall " " -> " n t
114+ sb env n (PVar t) = showb env "! " ". " n t
115+ sb env n (Let t v) = showbv env "let " " in " n t v
116+ sb env n (Guess t v) = showbv env "?? " " in " n t v
117+
118+ showb env op sc n t = op ++ show n ++ " : " ++ se 10 env t ++ sc
119+ showbv env op sc n t v = op ++ show n ++ " : " ++ se 10 env t ++ " = " ++
120+ se 10 env v ++ sc
121+
122+ bracket outer inner str | inner > outer = "(" ++ str ++ ")"
123+ | otherwise = str
124+
125+-- Check whether a term has any holes in it - impure if so
126+
127+pureTerm :: TT n -> Bool
128+pureTerm (App f t a) = pureTerm f && pureTerm t && pureTerm a
129+pureTerm (Bind n b sc) = pureBinder b && pureTerm sc where
130+ pureBinder (Hole _) = False
131+ pureBinder (Guess _ _) = False
132+ pureBinder (Let t v) = pureTerm t && pureTerm v
133+ pureBinder t = pureTerm (binderTy t)
134+pureTerm _ = True
135+
136+-- weaken a term by adding i to each de Bruijn index (i.e. lift it over i bindings)
137+
138+weakenTm :: Int -> TT n -> TT n
139+weakenTm i t = wk i 0 t
140+ where wk i min (V x) | x >= min = V (i + x)
141+ wk i m (App f t a) = App (wk i m f) (wk i m t) (wk i m a)
142+ wk i m (Bind x b sc) = Bind x (wkb i m b) (wk i (m + 1) sc)
143+ wk i m t = t
144+ wkb i m (Let t v) = Let (wk i m t) (wk i m v)
145+ wkb i m (Guess t v) = Guess (wk i m t) (wk i m v)
146+ wkb i m t = t { binderTy = wk i m (binderTy t) }
147+
148+-- weaken an environment so that all the de Bruijn indices are correct according
149+-- to the latest bound variable
150+
151+weakenEnv :: Show n => EnvTT n -> EnvTT n
152+weakenEnv env = wk (length env - 1) env
153+ where wk i [] = []
154+ wk i ((n, b) : bs) = (n, weakenTmB i b) : wk (i - 1) bs
155+ weakenTmB i (Let t v) = Let (weakenTm i t) (weakenTm i v)
156+ weakenTmB i (Guess t v) = Guess (weakenTm i t) (weakenTm i v)
157+ weakenTmB i t = t { binderTy = weakenTm i (binderTy t) }
112158
113159-- WELL TYPED TERMS AS HOAS -------------------------------------------------
114160
@@ -149,6 +195,10 @@ type Context = [(Name, Def)]
149195
150196emptyContext = []
151197
198+addToCtxt :: Name -> Term -> Type -> Context -> Context
199+addToCtxt n tm ty ctxt = (n, Function (Fun ty (hoas [] ty)
200+ tm (hoas [] tm))) : ctxt
201+
152202lookupTy :: Name -> Context -> Maybe Type
153203lookupTy n ctxt = do def <- lookup n ctxt
154204 case def of
src/ProofShell.hs+16−3
@@ -24,10 +24,23 @@ processCommand (Theorem n ty) state
2424 OK (gl, Set _) -> (state { prf = Just (newProof n (ctxt state) gl) }, "")
2525 OK _ -> (state, "Goal is not a type")
2626 err -> (state, show err)
27−processCommand Quit state = (state { exitNow = True }, "Bye bye")
28−processCommand (Tac t) state
27+processCommand Quit state = (state { exitNow = True }, "Bye bye")
28+processCommand (Eval t) state =
29+ case check (ctxt state) [] t of
30+ OK (val, _) ->
31+ let nf = normalise (ctxt state) [] val in
32+ (state, show nf)
33+ err -> (state, show err)
34+processCommand (Tac t) state
2935 | Just ps <- prf state = case processTactic t ps of
30− OK (ps', resp) -> (state { prf = Just ps' }, resp)
36+ OK (ps', resp) ->
37+ if (not (done ps'))
38+ then (state { prf = Just ps' }, resp)
39+ else (state { prf = Nothing,
40+ ctxt = addToCtxt (thname ps')
41+ (pterm ps')
42+ (ptype ps')
43+ (context ps') }, resp)
3144 err -> (state, show err)
3245 | otherwise = (state, "No proof in progress")
3346
src/ProofState.hs+102−50
@@ -5,14 +5,18 @@ module ProofState where
55import Typecheck
66import Evaluate
77import Core
8+
89import Control.Monad.State
10+import Control.Applicative
11+import Data.List
912
1013data ProofState = PS { thname :: Name,
1114 holes :: [Name], -- holes still to be solved
1215 nextname :: Int, -- name supply
1316 pterm :: Term, -- current proof term
17+ ptype :: Type, -- original goal
1418 context :: Context,
15− complete :: Bool
19+ done :: Bool
1620 }
1721
1822data Goal = GD { premises :: Env,
@@ -26,35 +30,59 @@ data Command = Theorem Name Raw
2630
2731data Tactic = Attack
2832 | Claim Name Raw
29− | Try Raw
33+ | Fill Raw
3034 | Regret
3135 | Solve
36+ | Intro Name
37+ | ProofState
3238 | QED
3339
40+data TacticAction = AddGoal Name
41+ | Solved Name
42+ | Log String
43+
44+-- Some utilites on proof and tactic states
45+
3446instance Show ProofState where
35− show (PS nm [] _ tm _ _) = show nm ++ ": no more goals"
36− show (PS nm (h:hs) _ tm ctxt _)
37− = let OK g = goal (Just h) tm ctxt in
38− showEnv (premises g) ++ "\n" ++
47+ show (PS nm [] _ tm _ _ _) = show nm ++ ": no more goals"
48+ show (PS nm (h:hs) _ tm _ ctxt _)
49+ = let OK g = goal (Just h) tm ctxt
50+ wkenv = weakenEnv (premises g) in
51+ showPs wkenv (reverse wkenv) ++ "\n" ++
3952 "-------------------------------- (" ++ show nm ++
4053 ") -------\n" ++
41− show h ++ " : " ++ showG (goalType g) ++ "\n"
42− where showEnv [] = ""
43− showEnv ((n, b):bs) = " " ++ show n ++ " : " ++ show (binderTy b) ++ "\n" ++
44− showEnv bs
45− showG (Guess t v) = show t ++ " =?= " ++ show v
46− showG b = show (binderTy b)
54+ show h ++ " : " ++ showG wkenv (goalType g) ++ "\n"
55+ where showPs env [] = ""
56+ showPs env ((n, b):bs)
57+ = " " ++ show n ++ " : " ++ showEnv env (binderTy b) ++
58+ "\n" ++ showPs env bs
59+ showG ps (Guess t v) = showEnv ps t ++ " =?= " ++ showEnv ps v
60+ showG ps b = showEnv ps (binderTy b)
61+
62+same Nothing n = True
63+same (Just x) n = x == n
64+
65+hole (Hole _) = True
66+hole (Guess _ _) = True
67+hole _ = False
4768
4869holeName i = MN i "hole"
4970
71+getName :: Monad m => String -> StateT TState m Name
72+getName tag = do (n, ts) <- get
73+ put (n+1, ts)
74+ return $ MN n tag
75+
76+action :: Monad m => TacticAction -> StateT TState m ()
77+action a = do (n, ts) <- get
78+ put (n, a:ts)
79+
5080newProof :: Name -> Context -> Type -> ProofState
5181newProof n ctxt ty = let h = holeName 0 in
52− PS n [h] 1 (Bind h (Hole ty) (V 0)) ctxt False
53−
54−data TacticAction = AddGoal Name
55− | Log String
82+ PS n [h] 1 (Bind h (Hole ty) (V 0)) ty ctxt False
5683
57−type RunTactic = Context -> Env -> Term -> StateT [TacticAction] TC Term
84+type TState = (Int, [TacticAction])
85+type RunTactic = Context -> Env -> Term -> StateT TState TC Term
5886type Hole = Maybe Name -- Nothing = default hole, first in list in proof state
5987
6088goal :: Hole -> Term -> Context -> TC Goal
@@ -68,34 +96,30 @@ goal h tm ctxt = g [] tm where
6896 gb env (Guess t v) = g env t `mplus` g env v
6997 gb env t = g env (binderTy t)
7098
71−tactic :: Hole -> Term -> Context -> RunTactic -> StateT [TacticAction] TC Term
72−tactic h tm ctxt f = atH [] tm where
99+tactic :: Hole -> ProofState -> Context -> RunTactic -> StateT TState TC ProofState
100+tactic h ps ctxt f = do let tm = pterm ps
101+ tm' <- atH [] tm
102+ return (ps { pterm = tm' })
103+ where
73104 atH env binder@(Bind n b sc)
74− | hole b && same h n = f ctxt env binder
75− | otherwise = do b' <- atHb env b
76− sc' <- atH ((n,b):env) sc
77− return (Bind n b' sc')
78− atH env (App f t a) = do f' <- atH env t; t' <- atH env t; a' <- atH env a
79− return (App f' t' a')
80− atH env t = do return t
105+ | hole b && same h n = f ctxt (weakenEnv env) binder
106+ | otherwise = pure Bind <*> pure n <*> atHb env b <*> atH ((n,b):env) sc
107+ atH env (App f t a) = pure App <*> atH env f <*> atH env t <*> atH env a
108+ atH env t = return t
81109
82− atHb env (Let t v) = do t' <- atH env t
83− v' <- atH env v
84− return $ Let t' v'
85− atHb env (Guess t v) = do t' <- atH env t
86− v' <- atH env v
87− return $ Let t' v'
110+ atHb env (Let t v) = pure Let <*> atH env t <*> atH env v
111+ atHb env (Guess t v) = pure Guess <*> atH env t <*> atH env v
88112 atHb env t = do ty' <- atH env (binderTy t)
89113 return $ t { binderTy = ty' }
90−
91−same Nothing n = True
92−same (Just x) n = x == n
93−
94−hole (Hole _) = True
95−hole (Guess _ _) = True
96114
97115attack :: RunTactic
98−attack = undefined
116+attack ctxt env (Bind x (Hole t) sc)
117+ = do h <- getName "hole"
118+ action (AddGoal h)
119+ return $ Bind x (Guess t (newtm h)) sc
120+ where
121+ newtm h = Bind h (Hole t) (V 0)
122+attack ctxt env _ = fail "Not an attackable hole"
99123
100124claim :: Name -> Raw -> RunTactic
101125claim = undefined
@@ -104,27 +128,55 @@ regret :: RunTactic
104128regret = undefined
105129
106130fill :: Raw -> RunTactic -- Try
107−fill = undefined
131+fill guess ctxt env (Bind x (Hole ty) sc) =
132+ do (val, valty) <- lift $ check ctxt env guess
133+ lift $ converts ctxt env valty ty
134+ return $ Bind x (Guess ty val) sc
135+fill _ _ _ _ = fail "Can't fill here."
108136
109137solve :: RunTactic
110−solve = undefined
138+solve ctxt env (Bind x (Guess ty val) sc)
139+ | pureTerm val = do action (Solved x)
140+ return $ Bind x (Let ty val) sc
141+ | otherwise = fail "I see a hole in your solution."
142+solve _ _ _ = fail "Not a guess."
143+
144+intro :: Name -> RunTactic
145+intro n ctxt env (Bind x (Hole t) (V 0)) =
146+ do let t' = normalise ctxt env t
147+ case t' of
148+ Bind y (Pi s) t -> return $ Bind n (Lam s) (Bind x (Hole t) (V 0))
149+ _ -> fail "Nothing to introduce"
150+intro ctxt env _ _ = fail "Can't introduce here."
111151
112152processTactic :: Tactic -> ProofState -> TC (ProofState, String)
113153processTactic QED ps = case holes ps of
114− [] -> return (ps { complete = True }, "QED")
115− _ -> Error "Still holes to fill"
154+ [] -> return (ps { done = True }, "Proof complete.")
155+ _ -> Error "Still holes to fill."
156+processTactic ProofState ps = return (ps, show (pterm ps))
116157processTactic t ps = case holes ps of
117− [] -> Error "Nothing to fill in"
118− (h:_) -> do (ps', actions) <- runStateT (process t h ps) []
119− return (ps', logs actions)
158+ [] -> Error "Nothing to fill in."
159+ (h:_) -> do let n = nextname ps
160+ (ps',(n', actions)) <- runStateT (process t h ps) (n, [])
161+ return (ps' { nextname = n',
162+ holes = goals (holes ps') actions },
163+ logs actions)
120164 where logs [] = ""
121165 logs (Log x : xs) = x ++ "\n" ++ logs xs
122166 logs (_ : xs) = logs xs
123167
124−process :: Tactic -> Name -> ProofState -> StateT [TacticAction] TC ProofState
125−process (Try x) h ps = undefined
126−
168+ goals g [] = g
169+ goals g (AddGoal n : xs) = goals (n : g) xs
170+ goals g (Solved n : xs) = goals (g \\ [n]) xs
171+ goals g (_ : xs) = goals g xs
127172
128−
129173
174+process :: Tactic -> Name -> ProofState -> StateT TState TC ProofState
175+process t h ps = tactic (Just h) ps (context ps) (mktac t)
176+ where mktac Attack = attack
177+ mktac (Claim n r) = claim n r
178+ mktac (Fill r) = fill r
179+ mktac Regret = regret
180+ mktac Solve = solve
181+ mktac (Intro n) = intro n
130182
src/ShellParser.hs+10−5
@@ -35,8 +35,8 @@ parseCommand = parse pCommand "(input)"
3535parseTactic = parse (pTactic >>= return . Tac) "(input)"
3636
3737pCommand :: Parser Command
38−pCommand = do reserved "theorem"; n <- identifier; lchar ':'; ty <- pTerm
39− return (Theorem (UN [n]) ty)
38+pCommand = do reserved "theorem"; n <- iname; lchar ':'; ty <- pTerm
39+ return (Theorem n ty)
4040 <|> do reserved "eval"; tm <- pTerm
4141 return (Eval tm)
4242 <|> do reserved "quit";
@@ -44,9 +44,14 @@ pCommand = do reserved "theorem"; n <- identifier; lchar ':'; ty <- pTerm
4444
4545pTactic :: Parser Tactic
4646pTactic = do reserved "attack"; return Attack
47− <|> do reserved "claim"; n <- identifier; lchar ':'; ty <- pTerm
48− return (Claim (UN [n]) ty)
49− <|> do reserved "try"; tm <- pTerm; return (Try tm)
47+ <|> do reserved "claim"; n <- iname; lchar ':'; ty <- pTerm
48+ return (Claim n ty)
49+ <|> do reserved "fill"; tm <- pTerm; return (Fill tm)
5050 <|> do reserved "regret"; return Regret
5151 <|> do reserved "solve"; return Solve
52+ <|> do reserved "intro"; n <- iname; return (Intro n)
53+ <|> do reserved "state"; return ProofState
5254 <|> do reserved "qed"; return QED
55+
56+iname :: Parser Name
57+iname = identifier >>= (\n -> return (UN [n]))
src/Typecheck.hs+2−1
@@ -1,4 +1,4 @@
1−{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
1+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor #-}
22
33module Typecheck where
44
@@ -10,6 +10,7 @@ import Evaluate
1010
1111data TC a = OK a
1212 | Error String -- TMP! Make this an informative data structure
13+ deriving (Eq, Functor)
1314
1415instance Show a => Show (TC a) where
1516 show (OK x) = show x