6 | import Language.Reflection.TTImp
7 | import Language.Reflection
13 | import Data.SnocList
17 | import Syntax.PreorderReasoning
21 | %language ElabReflection
31 | idTerm = `( (\ x => x
) )
33 | idTermTest : Auto.idTerm === let x : Name;
x = UN (Basic "x") in
34 | ILam ?
MW ExplicitArg (Just x) ?
(IVar ?
x)
40 | iLam : Maybe UserName -> TTImp -> TTImp -> TTImp
41 | iLam x a sc = ILam EmptyFC MW ExplicitArg (UN <$> x) a sc
43 | iVar : UserName -> TTImp
44 | iVar x = IVar EmptyFC (UN x)
49 | $
iLam (Just (Basic "v")) `(a)
53 | constTest : Auto.const 1 2 === 1
65 | let err = fail "No clue what to do"
68 | let mval = buildValue g
69 | maybe err check mval
73 | buildValue : TTImp -> Maybe TTImp
75 | let qNat : List ?
= [`{Nat
}, `{Prelude.Nat
}, `{Prelude.Types.Nat
}]
76 | let qBool : List ?
= [`{Bool
}, `{Prelude.Bool
}, `{Prelude.Basics.Bool
}]
77 | let qList : List ?
= [`{List
}, `{Prelude.List
}, `{Prelude.Basics.List
}]
78 | let qMaybe : List ?
= [`{Maybe
}, `{Prelude.Maybe
}, `{Prelude.Types.Maybe
}]
79 | let qPair : List ?
= [`{Pair
}, `{Builtin.Pair
}]
82 | ifThenElse (n `elem` qNat) (Just `(0)) $
83 | ifThenElse (n `elem` qBool) (Just `(False))
85 | IApp _ (IVar _ p) q =>
86 | ifThenElse (p `elem` qMaybe)
87 | (case buildValue q of
88 | Nothing => pure `(Nothing
)
89 | Just qv => pure `(Just ~(qv)))
90 | $
ifThenElse (p `elem` qList)
91 | (case buildValue q of
92 | Nothing => pure `([])
93 | Just qv => pure `([~(qv)]))
95 | IApp _ (IApp _ (IVar _ p) q) r =>
96 | ifThenElse (not (p `elem` qPair)) Nothing $
do
99 | pure `(MkPair ~(qv) ~(rv))
102 | getAPoint : (List Nat, (Bool, (Maybe (List Void, Bool, Nat))), Nat)
103 | getAPoint = %runElab getPoint
105 | getPointTest : Auto.getAPoint === ([0], (False, Just ([], False, 0)), 0)
106 | getPointTest = Refl
111 | data Even : Nat -> Type where
113 | EvenS : Even n -> Even (S (S n))
115 | EvenPlus : {0 m, n : Nat} -> Even m -> Even n -> Even (m + n)
116 | EvenPlus EvenZ en = en
117 | EvenPlus (EvenS em) en = EvenS (EvenPlus em en)
119 | trivial : Even n -> Even (n + 2)
120 | trivial en = EvenPlus en (EvenS EvenZ)
127 | HintDB = SnocList Name
130 | hints = [< `{EvenZ
}, `{EvenS
}, `{EvenPlus
}]
139 | data RuleName : Type where
140 | Free : Name -> RuleName
141 | Bound : Nat -> RuleName
144 | toName : RuleName -> Name
145 | toName (Free nm) = nm
146 | toName (Bound n) = DN (pack $
display n)
147 | $
MN "bound_variable_auto_search" (cast n)
150 | display : Nat -> List Char
152 | let (p, q) = divmodNatNZ n 26 ItIsSucc in
153 | cast (q + cast 'a') :: if p == 0 then [] else display (assert_smaller n (pred p))
157 | Show RuleName where
158 | show (Free nm) = "Free \{show nm}"
159 | show (Bound n) = "Bound \{show n}"
165 | data TermName : Type where
166 | UName : Name -> TermName
167 | Bound : Nat -> TermName
172 | UName n1 == UName n2 = n1 == n2
173 | Bound n1 == Bound n2 = n1 == n2
174 | Arrow == Arrow = True
179 | data Tm : Nat -> Type where
180 | Var : Fin n -> Tm n
181 | Con : TermName -> List (Tm n) -> Tm n
184 | showTerm : (ns : SnocList Name) -> Tm (length ns) -> String
185 | showTerm ns = go Open where
187 | goVar : (ns : SnocList Name) -> Fin (length ns) -> String
188 | goVar (_ :< n) FZ = show n
189 | goVar (ns :< _) (FS k) = goVar ns k
191 | go : Prec -> Tm (length ns) -> String
192 | go d (Var k) = goVar ns k
193 | go d (Con (UName n) []) = show n
194 | go d (Con Arrow [a,b])
195 | = showParens (d > Open) $
196 | unwords [ go App a, "->", go Open b ]
197 | go d (Con (UName n) [a,b])
198 | = showParens (d > Open) $
200 | if isOp n then unwords [ go App a, show n, go Open b ]
201 | else unwords [ show n, go App a, go App b ]
202 | go d (Con (UName n) ts)
203 | = showParens (d > Open) $
204 | unwords (show n :: assert_total (map (go App) ts))
208 | Env : (Nat -> Type) -> Nat -> Nat -> Type
209 | Env t m n = Fin m -> t n
212 | rename : Env Fin m n -> Tm m -> Tm n
213 | rename rho (Var x) = Var (rho x)
214 | rename rho (Con f xs) = Con f (assert_total $
map (rename rho) xs)
217 | subst : Env Tm m n -> Tm m -> Tm n
218 | subst rho (Var x) = rho x
219 | subst rho (Con f xs) = Con f (assert_total $
map (subst rho) xs)
222 | split : Tm m -> (List (Tm m), Tm m)
223 | split = go [<] where
225 | go : SnocList (Tm m) -> Tm m -> (List (Tm m), Tm m)
226 | go acc (Con Arrow [a,b]) = go (acc :< a) b
227 | go acc t = (acc <>> [], t)
234 | thin : Fin (S n) -> Fin n -> Fin (S n)
236 | thin (FS x) FZ = FZ
237 | thin (FS x) (FS y) = FS (thin x y)
240 | thinInjective : (x : Fin (S n)) -> (y, z : Fin n) -> thin x y === thin x z -> y === z
241 | thinInjective FZ y z eq = injective eq
242 | thinInjective (FS x) FZ FZ eq = Refl
243 | thinInjective (FS x) (FS y) (FS z) eq = cong FS (thinInjective x y z $
injective eq)
246 | {x : Fin (S n)} -> Injective (thin x) where
247 | injective = thinInjective x ? ?
250 | thinnedApart : (x : Fin (S n)) -> (y : Fin n) -> Not (thin x y === x)
251 | thinnedApart FZ y = absurd
252 | thinnedApart (FS x) FZ = absurd
253 | thinnedApart (FS x) (FS y) = thinnedApart x y . injective
256 | thinApart : (x, y : Fin (S n)) -> Not (x === y) -> (
y' ** thin x y' === y)
257 | thinApart FZ FZ neq = absurd (neq Refl)
258 | thinApart FZ (FS y') neq = (
y' ** Refl)
259 | thinApart (FS FZ) FZ neq = (
FZ ** Refl)
260 | thinApart (FS (FS x)) FZ neq = (
FZ ** Refl)
261 | thinApart (FS x@FZ) (FS y) neq = bimap FS (\prf => cong FS prf) (thinApart x y (\prf => neq $
cong FS prf))
262 | thinApart (FS x@(FS{})) (FS y) neq = bimap FS (\prf => cong FS prf) (thinApart x y (\prf => neq $
cong FS prf))
265 | data Thicken : (x, y : Fin n) -> Type where
267 | NEQ : (y : Fin n) -> Thicken x (thin x y)
270 | thicken : (x, y : Fin n) -> Thicken x y
272 | thicken FZ (FS y) = NEQ y
273 | thicken (FS FZ) FZ = NEQ FZ
274 | thicken (FS (FS{})) FZ = NEQ FZ
275 | thicken (FS x) (FS y) with (thicken x y)
276 | thicken (FS x) (FS x) | EQ = EQ
277 | thicken (FS x) (FS (thin x y)) | NEQ y = NEQ (FS y)
280 | check : Fin (S n) -> Tm (S n) -> Maybe (Tm n)
281 | check x (Var y) = case thicken x y of
283 | NEQ y' => Just (Var y')
284 | check x (Con f ts) = Con f <$> assert_total (traverse (check x) ts)
288 | for : Tm n -> Fin (S n) -> Env Tm (S n) n
289 | (t `for` x) y = case thicken x y of
294 | data AList : (m, n : Nat) -> Type where
296 | (:<) : AList m n -> (Fin (S m), Tm m) -> AList (S m) n
299 | (++) : AList m n -> AList l m -> AList l n
301 | xts ++ (yus :< yt) = (xts ++ yus) :< yt
304 | toSubst : AList m n -> Env Tm m n
306 | toSubst (xts :< (x , t)) = subst (toSubst xts) . (t `Auto.for` x)
308 | record Unifying m where
309 | constructor MkUnifying
311 | rho : AList m target
314 | flexFlex : {m : _} -> (x, y : Fin m) -> Unifying m
315 | flexFlex x y = case thicken x y of
316 | EQ => MkUnifying [<]
317 | NEQ y' => MkUnifying [<(x, Var y')]
319 | flexRigid : {m : _} -> (x : Fin m) -> (t : Tm m) -> Maybe (Unifying m)
321 | flexRigid x@FZ t = do
323 | Just (MkUnifying [<(x,t')])
324 | flexRigid x@(FS{}) t = do
326 | Just (MkUnifying [<(x,t')])
329 | mgu : {m : _} -> (s, t : Tm m) -> Maybe (Unifying m)
331 | amgu : {n : _} -> (s, t : Tm m) -> AList m n -> Maybe (Unifying m)
332 | amgus : {n : _} -> (s, t : List (Tm m)) -> AList m n -> Maybe (Unifying m)
334 | mgu s t = amgu s t [<]
336 | amgu (Con f ts) (Con g us) acc
337 | = do guard (f == g)
339 | amgu (Var x) (Var y) [<] = Just (flexFlex x y)
340 | amgu (Var x) t [<] = flexRigid x t
341 | amgu s (Var y) [<] = flexRigid y s
342 | amgu s t (rho :< (x, v)) = do
343 | let sig = v `for` x
344 | MkUnifying acc <- amgu (subst sig s) (subst sig t) rho
345 | Just (MkUnifying (acc :< (x, v)))
347 | amgus [] [] acc = Just (MkUnifying acc)
348 | amgus (t :: ts) (u :: us) acc = do
349 | MkUnifying acc <- amgu t u acc
351 | amgus _ _ _ = Nothing
360 | context : SnocList Name
361 | ruleName : RuleName
363 | premises : Vect arity (Tm (length context))
364 | conclusion : Tm (length context)
367 | (.scope) : Rule -> Nat
368 | r .scope = length r.context
372 | show (MkRule context nm premises conclusion)
374 | $
ifThenElse (null context) "" (" forall \{unwords (map show context <>> [])}.")
375 | :: map ((" " ++) . showTerm context) (toList premises)
376 | ++ [ replicate 25 '-' ++ " " ++ show nm
377 | , " " ++ showTerm context conclusion
386 | data Add : (m, n, p : Nat) -> Type where
387 | AddBase : Add 0 n n
388 | AddStep : Add m n p -> Add (S m) n (S p)
390 | add : Vect 3 (Tm m) -> Tm m
391 | add = Con (UName `{Search.Auto.Example.Add
}) . toList
394 | zro = Con (UName `{Prelude.Types.Z
}) []
396 | suc : Vect 1 (Tm m) -> Tm m
397 | suc = Con (UName `{Prelude.Types.S
}) . toList
401 | = MkRule [< UN (Basic "n")] (Free `{AddBase
})
404 | $
add [ zro, Var FZ, Var FZ ]
408 | = MkRule (UN . Basic <$> [<"m","n","p"]) (Free `{AddStep
})
409 | [add [Var 2, Var 1, Var 0]]
411 | $
add [suc [Var 2], Var 1, suc [Var 0]]
414 | addHints = [qAddBase, qAddStep]
423 | data Space : Type -> Type where
424 | Solution : a -> Space a
425 | Candidates : List (Inf (Space a)) -> Space a
431 | data Proof : Type where
432 | Call : RuleName -> List Proof -> Proof
433 | Lam : Nat -> Proof -> Proof
437 | show prf = unlines (go "" [<] prf <>> []) where
438 | go : (indent : String) -> SnocList String -> Proof -> SnocList String
439 | go indent acc (Call r prfs) =
440 | let acc = acc :< (indent ++ show r) in
441 | assert_total $
foldl (go (" " ++ indent)) acc prfs
442 | go indent acc (Lam n prf) =
443 | let acc = acc :< (indent ++ "\\ x" ++ show n) in
444 | assert_total $
go (" " ++ indent) acc prf
450 | record PartialProof (m : Nat) where
451 | constructor MkPartialProof
453 | goals : Vect leftovers (Tm m)
454 | continuation : Vect leftovers Proof -> Proof
458 | apply : (r : Rule) -> Vect (r.arity + k) Proof -> Vect (S k) Proof
459 | apply r args = let (premises, rest) = splitAt r.arity args in
460 | Call r.ruleName (toList premises) :: rest
462 | mkVars : (m : Nat) -> (vars : SnocList Name ** length vars = m)
463 | mkVars Z = (
[<] ** Refl)
464 | mkVars m@(S m') = bimap (:< UN (Basic $
"_invalidName" ++ show m)) (\prf => cong S prf) (mkVars m')
466 | solveAcc : {m : _} -> Nat -> HintDB -> PartialProof m -> Space Proof
467 | solveAcc idx rules (MkPartialProof 0 goals k)
469 | solveAcc idx rules (MkPartialProof (S ar) (Con Arrow [a, b] :: goals) k)
474 | = let (prems, res) = split a in
475 | let (
vars ** Refl)
= mkVars m in
476 | let rule = MkRule vars (Bound idx) (fromList prems) res in
477 | Candidates [ solveAcc (S idx) (rule :: rules)
478 | $
MkPartialProof (S ar) (b :: goals)
479 | $
\ (b :: prfs) => k (Lam idx b :: prfs)]
480 | solveAcc idx rules (MkPartialProof (S ar) (g :: goals) k)
481 | = Candidates (assert_total $
map step rules) where
483 | step : Rule -> Inf (Space Proof)
484 | step r with (mgu (rename (weakenN r.scope) g) (rename (shift m) (conclusion r)))
485 | _ | Nothing = Candidates []
486 | _ | Just sol = let sig = toSubst sol.rho in
487 | solveAcc idx rules $
MkPartialProof
489 | (map (subst (sig . shift m)) r.premises
490 | ++ map (subst (sig . weakenN r.scope)) goals)
496 | solve : {m : _} -> Nat -> HintDB -> Tm m -> Space Proof
497 | solve idx rules goal = solveAcc idx rules (MkPartialProof 1 [goal] head)
503 | dfs : (depth : Nat) -> Space a -> List a
504 | dfs _ (Solution x) = [x]
506 | dfs (S k) (Candidates cs) = cs >>= \ c => dfs k c
513 | $
solve {m = 0} 0 addHints
514 | $
add [ suc [suc [zro]]
516 | , suc [suc [suc [suc [zro]]]]
519 | lengthDistributesOverFish : (sx : SnocList a) -> (xs : List a) ->
520 | length (sx <>< xs) === length sx + length xs
521 | lengthDistributesOverFish sx [] = sym $
plusZeroRightNeutral ?
522 | lengthDistributesOverFish sx (x :: xs) = Calc $
523 | |~ length ((sx :< x) <>< xs)
524 | ~~ length (sx :< x) + length xs ...( lengthDistributesOverFish (sx :< x) xs)
525 | ~~ S (length sx) + length xs ...( Refl )
526 | ~~ length sx + S (length xs) ...( plusSuccRightSucc ? ?
)
527 | ~~ length sx + length (x :: xs) ...( Refl )
529 | convertVar : (vars : SnocList Name) -> Name -> Tm (length vars)
530 | convertVar [<] nm = Con (UName nm) []
531 | convertVar (sx :< x) nm = if x == nm then Var FZ else go sx [x] FZ
535 | go : (vars : SnocList Name) -> (ctxt : List Name) ->
536 | Fin (length ctxt) -> Tm (length (vars <>< ctxt))
537 | go [<] ctxt k = Con (UName nm) []
538 | go (sx :< x) ctxt k =
540 | then Var $
rewrite lengthDistributesOverFish sx (x :: ctxt) in
541 | rewrite plusCommutative (length sx) (S (length ctxt)) in
542 | weakenN (length sx) (FS k)
543 | else go sx (x :: ctxt) (FS k)
545 | skolemVar : SnocList Name -> Name -> Tm 0
546 | skolemVar [<] nm = Con (UName nm) []
547 | skolemVar (sx :< x) nm
548 | = if nm == x then Con (Bound (length sx)) [] else skolemVar sx nm
550 | getFnArgs : TTImp -> (TTImp, List TTImp)
551 | getFnArgs = go [] where
553 | go : List TTImp -> TTImp -> (TTImp, List TTImp)
554 | go acc (IApp _ f t) = go (t :: acc) f
555 | go acc (INamedApp _ f n t) = go acc f
556 | go acc (IAutoApp _ f t) = go acc f
557 | go acc t = (t, acc)
559 | parameters (0 f : SnocList Name -> Nat) (cvar : (vars : SnocList Name) -> Name -> Tm (f vars))
564 | convert : (vars : SnocList Name) -> TTImp -> Either TTImp (Tm (f vars))
565 | convert vars (IVar _ nm) = pure (cvar vars nm)
566 | convert vars t@(IApp x y z) = do
567 | let (IVar _ nm, args) = getFnArgs t
569 | let (Con nm []) = convertVar vars nm
571 | Con nm <$> assert_total (traverse (convert vars) args)
572 | convert vars t@(IPi _ _ ExplicitArg (Just n@(UN{})) argTy retTy) = Left t
573 | convert vars (IPi _ _ ExplicitArg _ argTy retTy)
574 | = do a <- convert vars argTy
575 | b <- convert vars retTy
576 | pure (Con Arrow [a,b])
577 | convert vars t = Left t
584 | parseType : TTImp -> Either TTImp (vars : SnocList Name ** Tm (f vars))
585 | parseType = go [<] where
587 | go : SnocList Name -> TTImp -> Either TTImp (vars : SnocList Name ** Tm (f vars))
588 | go vars (IPi _ _ ImplicitArg mn _ retTy)
589 | = go (vars :< fromMaybe (UN Underscore) mn) retTy
590 | go vars t = map (MkDPair vars) (convert vars t)
594 | parseRule : TTImp -> Either TTImp (vars : SnocList Name ** Tm (length vars))
595 | parseRule = parseType length convertVar
599 | parseGoal : TTImp -> Either TTImp (SnocList Name, Tm 0)
601 | (
vars ** g)
<- parseType (\ _ => 0) skolemVar t
605 | mkRule : Name -> Elab Rule
607 | [(_, ty)] <- getType nm
608 | | [] => fail "Couldn't find \{show nm}."
609 | | nms => fail $
concat
610 | $
"Ambiguous name \{show nm}, could be any of: "
611 | :: intersperse ", " (map (show . fst) nms)
612 | logMsg (show nm) 1 "Found the definition."
613 | let Right (
m ** tm)
= parseRule ty
614 | | Left t => fail "The type of \{show nm} is unsupported, chocked on \{show t}"
615 | logMsg (show nm) 1 "Parsed the type."
616 | let (premises, goal) = split tm
617 | logMsg (show nm) 1 "Successfully split the type."
618 | let r = MkRule m (Free nm) (fromList premises) goal
619 | logMsg "auto.quoting.\{show nm}" 1 ("\n" ++ show r)
625 | evenHints = with [Prelude.(::), Prelude.Nil]
626 | [ %runElab (mkRule `{EvenZ
})
627 | , %runElab (mkRule `{EvenS
})
628 | , %runElab (mkRule `{EvenPlus
})
632 | getGoal : Elab (HintDB, Tm 0)
635 | | Nothing => fail "No goal to get"
636 | let Right (vars, qgty) = parseGoal gty
637 | | Left t => fail "Couldn't parse goal type: \{show t}"
638 | let (qass, qg) = split qgty
639 | pure (toPremises (length vars) qass, qg)
642 | toPremises : Nat -> List (Tm 0) -> HintDB
643 | toPremises acc [] = []
644 | toPremises acc (t :: ts)
645 | = let (prems, res) = split t in
646 | MkRule [<] (Bound acc) (fromList prems) res :: toPremises (S acc) ts
649 | unquote : Proof -> TTImp
650 | unquote (Call f xs)
651 | = foldl (IApp emptyFC) (IVar emptyFC (toName f))
652 | $
assert_total (map unquote xs)
653 | unquote (Lam n prf)
654 | = ILam emptyFC MW ExplicitArg (Just $
toName (Bound n)) (Implicit emptyFC False)
658 | intros : List a -> TTImp -> TTImp
659 | intros = go 0 where
661 | go : Nat -> List a -> TTImp -> TTImp
664 | = ILam emptyFC MW ExplicitArg (Just $
toName (Bound idx)) (Implicit emptyFC False)
668 | bySearch : (depth : Nat) -> HintDB -> Elab a
669 | bySearch depth rules = do
670 | (rules', g) <- getGoal
671 | logMsg "auto.search.goal" 1 (showTerm [<] g)
672 | let rules = rules ++ rules'
673 | logMsg "auto.search.rules" 1 (unlines $
map show rules')
674 | let (prf :: _) = dfs depth (solve (length rules') rules g)
675 | | _ => fail "Couldn't find proof for goal"
676 | check (intros rules' (unquote prf))
681 | idTest = %runElab (bySearch 2 [])
683 | constTest : a -> b -> a
684 | constTest = %runElab (bySearch 2 [])
686 | sTest : (a -> b -> c) -> (a -> b) -> a -> c
687 | sTest = %runElab (bySearch 4 [])
691 | mkPair : a -> b -> Pair a b
692 | mkPair a b = (a, b)
694 | listFromDupTest : (a -> (a -> (a, a)) -> List a) -> a -> List a
695 | listFromDupTest = %runElab (bySearch 6 [%runElab (mkRule `{mkPair
})])
698 | even0Test = %runElab (bySearch 1 evenHints)
701 | even2Test = %runElab (bySearch 2 evenHints)
703 | evenPlusTest : Even n -> Even m -> Even (m + n)
704 | evenPlusTest = %runElab (bySearch 3 evenHints)
706 | evenPlus2Test : Even m -> Even (m + 2)
707 | evenPlus2Test = %runElab (bySearch 4 evenHints)
709 | addBaseTest : Add Z Z Z
710 | addBaseTest = %runElab (bySearch 3 addHints)
712 | add2TwiceTest : Add 2 2 4
713 | add2TwiceTest = %runElab (bySearch 3 addHints)