1{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, PatternGuards #-}
3{- Implements a proof state, some primitive tactics for manipulating
4 proofs, and some high level commands for introducing new theorems,
5 evaluation/checking inside the proof system, etc. --}
7module Core.ProofState(ProofState(..), newProof, envAtFocus, goalAtFocus,
8 Tactic(..), Goal(..), processTactic, dropGiven) where
15import Control.Monad.State
16import Control.Applicative hiding (empty)
22data ProofState = PS { thname :: Name,
23 holes :: [Name], -- holes still to be solved
24 usedns :: [Name], -- used names, don't use again
25 nextname :: Int, -- name supply
26 pterm :: Term, -- current proof term
27 ptype :: Type, -- original goal
28 dontunify :: [Name], -- explicitly given by programmer, leave it
29 unified :: (Name, [(Name, Term)]),
30 solved :: Maybe (Name, Term),
32 injective :: [(Term, Term, Term)],
33 deferred :: [Name], -- names we'll need to define
34 instances :: [Name], -- instance arguments (for type classes)
35 previous :: Maybe ProofState, -- for undo
41data Goal = GD { premises :: Env,
42 goalType :: Binder Term
50 | PrepFill Name [Name]
60 | IntroTy Raw (Maybe Name)
62 | LetBind Name Raw Raw
68 | DeferType Name Raw [Name]
76-- Some utilites on proof and tactic states
78instance Show ProofState where
79 show (PS nm [] _ _ tm _ _ _ _ _ _ _ _ _ _ _ _) = show nm ++ ": no more goals"
80 show (PS nm (h:hs) _ _ tm _ _ _ _ _ _ i _ _ ctxt _ _)
81 = let OK g = goal (Just h) tm
83 "Other goals: " ++ show hs ++ "\n" ++
84 showPs wkenv (reverse wkenv) ++ "\n" ++
85 "-------------------------------- (" ++ show nm ++
87 show h ++ " : " ++ showG wkenv (goalType g) ++ "\n"
88 where showPs env [] = ""
89 showPs env ((n, Let t v):bs)
90 = " " ++ show n ++ " : " ++
91 showEnv env ({- normalise ctxt env -} t) ++ " = " ++
92 showEnv env ({- normalise ctxt env -} v) ++
94 showPs env ((n, b):bs)
95 = " " ++ show n ++ " : " ++
96 showEnv env ({- normalise ctxt env -} (binderTy b)) ++
98 showG ps (Guess t v) = showEnv ps ({- normalise ctxt ps -} t) ++
99 " =?= " ++ showEnv ps v
100 showG ps b = showEnv ps (binderTy b)
102instance Pretty ProofState where
103 pretty (PS nm [] _ _ trm _ _ _ _ _ _ _ _ _ _ _ _) =
104 if size nm > breakingSize then
105 pretty nm <> colon $$ nest nestingSize (text " no more goals.")
107 pretty nm <> colon <+> text " no more goals."
108 pretty p@(PS nm (h:hs) _ _ tm _ _ _ _ _ _ i _ _ ctxt _ _) =
109 let OK g = goal (Just h) tm in
110 let wkEnv = premises g in
111 text "Other goals" <+> colon <+> pretty hs $$
112 prettyPs wkEnv (reverse wkEnv) $$
113 text "---------- " <+> text "Focussing on" <> colon <+> pretty nm <+> text " ----------" $$
114 pretty h <+> colon <+> prettyGoal wkEnv (goalType g)
116 prettyGoal ps (Guess t v) =
117 if size v > breakingSize then
118 prettyEnv ps t <+> text "=?=" $$
119 nest nestingSize (prettyEnv ps v)
121 prettyEnv ps t <+> text "=?=" <+> prettyEnv ps v
122 prettyGoal ps b = prettyEnv ps $ binderTy b
124 prettyPs env [] = empty
125 prettyPs env ((n, Let t v):bs) =
126 nest nestingSize (pretty n <+> colon <+>
127 if size v > breakingSize then
128 prettyEnv env t <+> text "=" $$
129 nest nestingSize (prettyEnv env v) $$
130 nest nestingSize (prettyPs env bs)
132 prettyEnv env t <+> text "=" <+> prettyEnv env v $$
133 nest nestingSize (prettyPs env bs))
134 prettyPs env ((n, b):bs) =
135 if size (binderTy b) > breakingSize then
136 nest nestingSize (pretty n <+> colon <+> prettyEnv env (binderTy b) <+> prettyPs env bs)
138 nest nestingSize (pretty n <+> colon <+> prettyEnv env (binderTy b) $$
139 nest nestingSize (prettyPs env bs))
142same (Just x) n = x == n
145hole (Guess _ _) = True
148holeName i = MN i "hole"
150unify' :: Context -> Env -> TT Name -> TT Name -> StateT TState TC [(Name, TT Name)]
151unify' ctxt env topx topy = do (u, inj, fails) <- lift $ unify ctxt env topx topy
157 put (ps { problems = err ++ problems ps })
160getName :: Monad m => String -> StateT TState m Name
161getName tag = do ps <- get
163 put (ps { nextname = n+1 })
166action :: Monad m => (ProofState -> ProofState) -> StateT TState m ()
167action a = do ps <- get
170addLog :: Monad m => String -> StateT TState m ()
171addLog str = action (\ps -> ps { plog = plog ps ++ str ++ "\n" })
173newProof :: Name -> Context -> Type -> ProofState
174newProof n ctxt ty = let h = holeName 0
176 PS n [h] [] 1 (Bind h (Hole ty')
177 (P Bound h ty')) ty [] (h, [])
180 Nothing ctxt "" False
182type TState = ProofState -- [TacticAction])
183type RunTactic = Context -> Env -> Term -> StateT TState TC Term
184type Hole = Maybe Name -- Nothing = default hole, first in list in proof state
186envAtFocus :: ProofState -> TC Env
188 | not $ null (holes ps) = do g <- goal (Just (head (holes ps))) (pterm ps)
190 | otherwise = fail "No holes"
192goalAtFocus :: ProofState -> TC (Binder Type)
194 | not $ null (holes ps) = do g <- goal (Just (head (holes ps))) (pterm ps)
197goal :: Hole -> Term -> TC Goal
198goal h tm = g [] tm where
199 g env (Bind n b sc) | hole b && same h n = return $ GD env b
201 = gb env b `mplus` g ((n, b):env) sc
202 g env (App f a) = g env f `mplus` g env a
203 g env t = fail "Can't find hole"
205 gb env (Let t v) = g env t `mplus` g env v
206 gb env (Guess t v) = g env t `mplus` g env v
207 gb env t = g env (binderTy t)
209tactic :: Hole -> RunTactic -> StateT TState TC ()
210tactic h f = do ps <- get
211 tm' <- atH (context ps) [] (pterm ps)
212 ps <- get -- might have changed while processing
213 put (ps { pterm = tm' })
215 atH c env binder@(Bind n b sc)
216 | hole b && same h n = f c env binder
218 = liftM2 (Bind n) (atHb c env b) (atH c ((n, b) : env) sc)
219 atH c env (App f a) = liftM2 App (atH c env f) (atH c env a)
220 atH c env t = return t
222 atHb c env (Let t v) = liftM2 Let (atH c env t) (atH c env v)
223 atHb c env (Guess t v) = liftM2 Guess (atH c env t) (atH c env v)
224 atHb c env t = do ty' <- atH c env (binderTy t)
225 return $ t { binderTy = ty' }
228attack ctxt env (Bind x (Hole t) sc)
229 = do h <- getName "hole"
230 action (\ps -> ps { holes = h : holes ps })
231 return $ Bind x (Guess t (newtm h)) sc
233 newtm h = Bind h (Hole t) (P Bound h t)
234attack ctxt env _ = fail "Not an attackable hole"
236claim :: Name -> Raw -> RunTactic
237claim n ty ctxt env t =
238 do (tyv, tyt) <- lift $ check ctxt env ty
239 lift $ isType ctxt env tyt
240 action (\ps -> let (g:gs) = holes ps in
241 ps { holes = g : n : gs } )
242 return $ Bind n (Hole tyv) t -- (weakenTm 1 t)
244reorder_claims :: RunTactic
245reorder_claims ctxt env t
246 = -- trace (showSep "\n" (map show (scvs t))) $
247 let (bs, sc) = scvs t []
248 newbs = reverse (sortB (reverse bs)) in
249 traceWhen (bs /= newbs) (show bs ++ "\n ==> \n" ++ show newbs) $
250 return (bindAll newbs sc)
251 where scvs (Bind n b@(Hole _) sc) acc = scvs sc ((n, b):acc)
252 scvs sc acc = (reverse acc, sc)
254 sortB :: [(Name, Binder (TT Name))] -> [(Name, Binder (TT Name))]
256 sortB (x:xs) | all (noOcc x) xs = x : sortB xs
257 | otherwise = sortB (insertB x xs)
260 insertB x (y:ys) | all (noOcc x) (y:ys) = x : y : ys
261 | otherwise = y : insertB x ys
263 noOcc (n, _) (_, Let t v) = noOccurrence n t && noOccurrence n v
264 noOcc (n, _) (_, Guess t v) = noOccurrence n t && noOccurrence n v
265 noOcc (n, _) (_, b) = noOccurrence n (binderTy b)
267focus :: Name -> RunTactic
268focus n ctxt env t = do action (\ps -> let hs = holes ps in
270 then ps { holes = n : (hs \\ [n]) }
275movelast :: Name -> RunTactic
276movelast n ctxt env t = do action (\ps -> let hs = holes ps in
278 then ps { holes = (hs \\ [n]) ++ [n] }
282instanceArg :: Name -> RunTactic
283instanceArg n ctxt env (Bind x (Hole t) sc)
284 = do action (\ps -> let hs = holes ps
286 ps { holes = (hs \\ [x]) ++ [x],
288 return (Bind x (Hole t) sc)
290defer :: Name -> RunTactic
291defer n ctxt env (Bind x (Hole t) (P nt x' ty)) | x == x' =
292 do action (\ps -> let hs = holes ps in
293 ps { holes = hs \\ [x] })
294 return (Bind n (GHole (mkTy (reverse env) t))
295 (mkApp (P Ref n ty) (map getP (reverse env))))
298 mkTy ((n,b) : bs) t = Bind n (Pi (binderTy b)) (mkTy bs t)
300 getP (n, b) = P Bound n (binderTy b)
302-- as defer, but build the type and application explicitly
303deferType :: Name -> Raw -> [Name] -> RunTactic
304deferType n fty_in args ctxt env (Bind x (Hole t) (P nt x' ty)) | x == x' =
305 do (fty, _) <- lift $ check ctxt env fty_in
306 action (\ps -> let hs = holes ps
308 ps { holes = hs \\ [x],
310 return (Bind n (GHole fty)
311 (mkApp (P Ref n ty) (map getP args)))
313 getP n = case lookup n env of
314 Just b -> P Bound n (binderTy b)
315 Nothing -> error ("deferType can't find " ++ show n)
318regret ctxt env (Bind x (Hole t) sc) | noOccurrence x sc =
319 do action (\ps -> let hs = holes ps in
320 ps { holes = hs \\ [x] })
322regret ctxt env (Bind x (Hole t) _) = fail $ show x ++ " : " ++ show t ++ " is not solved"
324addInj :: [(Term, Term, Term)] -> StateT TState TC ()
325addInj inj = do ps <- get
326 put (ps { injective = inj ++ injective ps })
328exact :: Raw -> RunTactic
329exact guess ctxt env (Bind x (Hole ty) sc) =
330 do (val, valty) <- lift $ check ctxt env guess
331 lift $ converts ctxt env valty ty
332 return $ Bind x (Guess ty val) sc
333exact _ _ _ _ = fail "Can't fill here."
335-- As exact, but attempts to solve other goals by unification
337fill :: Raw -> RunTactic
338fill guess ctxt env (Bind x (Hole ty) sc) =
339 do (val, valty) <- lift $ check ctxt env guess
341-- let valtyn = normalise ctxt env valty
342-- let tyn = normalise ctxt env ty
343 ns <- unify' ctxt env valty ty
345 let (uh, uns) = unified ps
346 put (ps { unified = (uh, uns ++ ns) })
347-- addLog (show (uh, uns ++ ns))
348 return $ Bind x (Guess ty val) sc
349fill _ _ _ _ = fail "Can't fill here."
351prep_fill :: Name -> [Name] -> RunTactic
352prep_fill f as ctxt env (Bind x (Hole ty) sc) =
353 do let val = mkApp (P Ref f Erased) (map (\n -> P Ref n Erased) as)
354 return $ Bind x (Guess ty val) sc
355prep_fill f as ctxt env t = fail $ "Can't prepare fill at " ++ show t
357complete_fill :: RunTactic
358complete_fill ctxt env (Bind x (Guess ty val) sc) =
359 do let guess = forget val
360 (val', valty) <- lift $ check ctxt env guess
361 ns <- unify' ctxt env valty ty
363 let (uh, uns) = unified ps
364 put (ps { unified = (uh, uns ++ ns) })
365 return $ Bind x (Guess ty val) sc
366complete_fill ctxt env t = fail $ "Can't complete fill at " ++ show t
369solve ctxt env (Bind x (Guess ty val) sc)
370 | pureTerm val = do ps <- get
371 let (uh, uns) = unified ps
372 action (\ps -> ps { holes = holes ps \\ [x],
373 solved = Just (x, val),
374 -- dontunify = dontunify ps \\ [x],
375 -- unified = (uh, uns ++ [(x, val)]),
376 instances = instances ps \\ [x] })
377 return $ {- Bind x (Let ty val) sc -}
378 instantiate val (pToV x sc)
379 | otherwise = lift $ tfail $ IncompleteTerm val
380solve _ _ h = do ps <- get
381 fail $ "Not a guess " ++ show h ++ "\n" ++ show (holes ps, pterm ps)
383introTy :: Raw -> Maybe Name -> RunTactic
384introTy ty mn ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
385 do let n = case mn of
389 x@(Bind y (Pi s) _) -> x
390 _ -> normalise ctxt env t
391 (tyv, tyt) <- lift $ check ctxt env ty
392-- ns <- lift $ unify ctxt env tyv t'
394 Bind y (Pi s) t -> let t' = instantiate (P Bound n s) (pToV y t) in
395 do ns <- unify' ctxt env s tyv
397 let (uh, uns) = unified ps
398 put (ps { unified = (uh, uns ++ ns) })
399 return $ Bind n (Lam tyv) (Bind x (Hole t') (P Bound x t'))
400 _ -> fail "Nothing to introduce"
401introTy ty n ctxt env _ = fail "Can't introduce here."
403intro :: Maybe Name -> RunTactic
404intro mn ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
405 do let n = case mn of
409 x@(Bind y (Pi s) _) -> x
410 _ -> normalise ctxt env t
412 Bind y (Pi s) t -> -- trace ("in type " ++ show t') $
413 let t' = instantiate (P Bound n s) (pToV y t) in
414 return $ Bind n (Lam s) (Bind x (Hole t') (P Bound x t'))
415 _ -> fail "Nothing to introduce"
416intro n ctxt env _ = fail "Can't introduce here."
418forall :: Name -> Raw -> RunTactic
419forall n ty ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
420 do (tyv, tyt) <- lift $ check ctxt env ty
421 lift $ isType ctxt env tyt
422 lift $ isType ctxt env t
423 return $ Bind n (Pi tyv) (Bind x (Hole t) (P Bound x t))
424forall n ty ctxt env _ = fail "Can't pi bind here"
426patvar :: Name -> RunTactic
427patvar n ctxt env (Bind x (Hole t) sc) =
428 do action (\ps -> ps { holes = holes ps \\ [x] })
429 return $ Bind n (PVar t) (instantiate (P Bound n t) (pToV x sc))
430patvar n ctxt env tm = fail $ "Can't add pattern var at " ++ show tm
432letbind :: Name -> Raw -> Raw -> RunTactic
433letbind n ty val ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
434 do (tyv, tyt) <- lift $ check ctxt env ty
435 (valv, valt) <- lift $ check ctxt env val
436 lift $ isType ctxt env tyt
437 return $ Bind n (Let tyv valv) (Bind x (Hole t) (P Bound x t))
438letbind n ty val ctxt env _ = fail "Can't let bind here"
440rewrite :: Raw -> RunTactic
441rewrite tm ctxt env (Bind x (Hole t) xp@(P _ x' _)) | x == x' =
442 do (tmv, tmt) <- lift $ check ctxt env tm
443 let tmt' = normalise ctxt env tmt
445 (P _ (UN "=") _, [lt,rt,l,r]) ->
446 do let p = Bind rname (Lam lt) (mkP (P Bound rname lt) r l t)
447 let newt = mkP l r l t
448 let sc = forget $ (Bind x (Hole newt)
449 (mkApp (P Ref (UN "replace") (TType (UVal 0)))
450 [lt, l, r, p, tmv, xp]))
451 (scv, sct) <- lift $ check ctxt env sc
453 _ -> fail "Not an equality type"
455 -- to make the P for rewrite, replace syntactic occurrences of l in ty with
456 -- an x, and put \x : lt in front
457 mkP lt l r ty | l == ty = lt
458 mkP lt l r (App f a) = let f' = if (r /= f) then mkP lt l r f else f
459 a' = if (r /= a) then mkP lt l r a else a in
461 mkP lt l r (Bind n b sc)
463 sc' = if (r /= sc) then mkP lt l r sc else sc in
465 where mkPB (Let t v) = let t' = if (r /= t) then mkP lt l r t else t
466 v' = if (r /= v) then mkP lt l r v else v in
468 mkPB b = let ty = binderTy b
469 ty' = if (r /= ty) then mkP lt l r ty else ty in
473 rname = MN 0 "replaced"
474rewrite _ _ _ _ = fail "Can't rewrite here"
476patbind :: Name -> RunTactic
477patbind n ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
478 do let t' = case t of
479 x@(Bind y (PVTy s) t) -> x
480 _ -> normalise ctxt env t
482 Bind y (PVTy s) t -> let t' = instantiate (P Bound n s) (pToV y t) in
483 return $ Bind n (PVar s) (Bind x (Hole t') (P Bound x t'))
484 _ -> fail "Nothing to pattern bind"
485patbind n ctxt env _ = fail "Can't pattern bind here"
488compute ctxt env (Bind x (Hole ty) sc) =
489 do return $ Bind x (Hole (normalise ctxt env ty)) sc
491check_in :: Raw -> RunTactic
492check_in t ctxt env tm =
493 do (val, valty) <- lift $ check ctxt env t
494 addLog (showEnv env val ++ " : " ++ showEnv env valty)
497eval_in :: Raw -> RunTactic
498eval_in t ctxt env tm =
499 do (val, valty) <- lift $ check ctxt env t
500 let val' = normalise ctxt env val
501 let valty' = normalise ctxt env valty
502 addLog (showEnv env val ++ " : " ++
504-- " in " ++ show env ++
506 showEnv env val' ++ " : " ++
510start_unify :: Name -> RunTactic
511start_unify n ctxt env tm = do action (\ps -> ps { unified = (n, []) })
514tmap f (a, b, c) = (f a, b, c)
516solve_unified :: RunTactic
517solve_unified ctxt env tm =
519 let (_, ns) = unified ps
520 let unify = dropGiven (dontunify ps) ns
521 action (\ps -> ps { holes = holes ps \\ map fst unify })
522 action (\ps -> ps { pterm = updateSolved unify (pterm ps) })
523 action (\ps -> ps { injective = map (tmap (updateSolved unify)) (injective ps) })
524 return (updateSolved unify tm)
528dropGiven du ((n, P Bound t ty) : us) | n `elem` du && not (t `elem` du)
529 = (t, P Bound n ty) : dropGiven du us
530dropGiven du (u@(n, _) : us) | n `elem` du = dropGiven du us
531-- dropGiven du (u@(_, P a n ty) : us) | n `elem` du = dropGiven du us
532dropGiven du (u : us) = u : dropGiven du us
534updateSolved xs x = -- trace ("Updating " ++ show xs ++ " in " ++ show x) $
536updateSolved' xs (Bind n (Hole ty) t)
537 | Just v <- lookup n xs = instantiate v (pToV n (updateSolved' xs t))
538updateSolved' xs (Bind n b t)
539 | otherwise = Bind n (fmap (updateSolved' xs) b) (updateSolved' xs t)
540updateSolved' xs (App f a) = App (updateSolved' xs f) (updateSolved' xs a)
541updateSolved' xs (P _ n _)
542 | Just v <- lookup n xs = v
543updateSolved' xs t = t
545updateProblems ns [] = []
546updateProblems ns ((x, y, env, err) : ps) =
547 let x' = updateSolved ns x
548 y' = updateSolved ns y in
549 (x',y',env,err) : updateProblems ns ps
551processTactic :: Tactic -> ProofState -> TC (ProofState, String)
552processTactic QED ps = case holes ps of
553 [] -> do let tm = {- normalise (context ps) [] -} (pterm ps)
554 (tm', ty', _) <- recheck (context ps) [] (forget tm) tm
555 return (ps { done = True, pterm = tm' },
556 "Proof complete: " ++ showEnv [] tm')
557 _ -> fail "Still holes to fill."
558processTactic ProofState ps = return (ps, showEnv [] (pterm ps))
559processTactic Undo ps = case previous ps of
560 Nothing -> fail "Nothing to undo."
561 Just pold -> return (pold, "")
562processTactic EndUnify ps
563 = let (h, ns_in) = unified ps
564 ns = dropGiven (dontunify ps) ns_in
565 ns' = map (\ (n, t) -> (n, updateSolved ns t)) ns
566 tm' = -- trace ("Updating " ++ show ns') $ -- ++ " in " ++ show (pterm ps)) $
567 updateSolved ns' (pterm ps)
568 probs' = updateProblems ns' (problems ps) in
570 [] -> return (ps { pterm = tm',
572 injective = map (tmap (updateSolved ns'))
574 holes = holes ps \\ map fst ns' }, "")
575 errs@((_,_,_,err):_) -> tfail err
576processTactic (Reorder n) ps
577 = do ps' <- execStateT (tactic (Just n) reorder_claims) ps
578 return (ps' { previous = Just ps, plog = "" }, plog ps')
581 [] -> fail "Nothing to fill in."
582 (h:_) -> do ps' <- execStateT (process t h) ps
583 let pterm' = case solved ps' of
584 Just s -> updateSolved [s] (pterm ps')
586 return (ps' { pterm = pterm',
588 previous = Just ps, plog = "" }, plog ps')
590process :: Tactic -> Name -> StateT TState TC ()
593 let (h, _) = unified ps
594 tactic (Just h) solve_unified
595process t h = tactic (Just h) (mktac t)
596 where mktac Attack = attack
597 mktac (Claim n r) = claim n r
598 mktac (Exact r) = exact r
599 mktac (Fill r) = fill r
600 mktac (PrepFill n ns) = prep_fill n ns
601 mktac CompleteFill = complete_fill
602 mktac Regret = regret
604 mktac (StartUnify n) = start_unify n
605 mktac Compute = compute
606 mktac (Intro n) = intro n
607 mktac (IntroTy ty n) = introTy ty n
608 mktac (Forall n t) = forall n t
609 mktac (LetBind n t v) = letbind n t v
610 mktac (Rewrite t) = rewrite t
611 mktac (PatVar n) = patvar n
612 mktac (PatBind n) = patbind n
613 mktac (CheckIn r) = check_in r
614 mktac (EvalIn r) = eval_in r
615 mktac (Focus n) = focus n
616 mktac (Defer n) = defer n
617 mktac (DeferType n t a) = deferType n t a
618 mktac (Instance n) = instanceArg n
619 mktac (MoveLast n) = movelast n
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list