@@ -0,0 +1,122 @@
1+module Pruviloj.Injective
3+import Language.Reflection.Utils
6+import Pruviloj.Internals
7+import Pruviloj.Renamers
16+||| Compute the name for a constructor's injectivity lemma
17+injName : TTName -> TTName
18+injName cn = NS (SN (MetaN `{{injectivity}} cn)) ["Injective", "Pruviloj"]
20+||| Provide an error message for when non-constructor names are passed
21+notConstructor : TTName -> Elab a
22+notConstructor c = fail [NamePart c, TextPart "is not a constructor"]
25+getInjectivity : (cn : TTName) -> Elab TTName
26+getInjectivity cn = exists <|> declare
27+ where exists : Elab TTName
28+ exists = do (fn, Ref, _) <- lookupTyExact (injName cn)
29+ | (fn, _, _) => fail [TextPart "Bad earlier declaration of", NamePart fn]
33+ declare : Elab TTName
34+ declare = do (cn', DCon _ _, cty) <- lookupTyExact cn
35+ | _ => notConstructor cn
37+ (args1, res1) <- stealBindings !(forgetTypes cty) noRenames
38+ (args2, res2) <- stealBindings !(forgetTypes cty) noRenames
39+ let impls1 = map (\(n, b) => MkFunArg n (binderTy b) Implicit NotErased)
41+ let impls2 = map (\(n, b) => MkFunArg n (binderTy b) Implicit NotErased)
43+ let res = foldr (\t1, t2 => RApp (RApp (Var `{Pair}) t1) t2)
46+ `((=) {A=~(argTy a1)}
49+ ~(Var (argName a2))))
52+ declareType $ Declare fn (impls1 ++ impls2 ++
53+ [ MkFunArg !(gensym "arg")
57+ (map (Var . fst) args1))
59+ (map (Var . fst) args2)))
64+ clause <- elabPatternClause
65+ (do ((_, h)::_) <- reverse <$>
67+ (replicate (2 * length args1)
70+ | _ => fail [TextPart "Missing hole"]
73+ search -- rhs is conjunction of Refls
75+ DefineFun fn [clause]
78+countBinders : TT -> Nat
79+countBinders (Bind _ _ body) = S (countBinders body)
83+----------------------
84+-- PUBLIC INTERFACE --
85+----------------------
88+||| Given an equality of the form `(C x1 ... xn = C y1 ... yn)`,
89+||| generate an product of the equalities `(x1 = y1)` ... `(xn = yn)`.
91+||| The equalities are let-bound to the provided name.
93+||| @ tm the equality to exploit injectivity on
94+||| @ n the name at which to bind the result
96+injective : (tm : Raw) -> (n : TTName) -> Elab ()
98+ do (_, ty) <- check tm
99+ case !(forgetTypes ty) of
100+ `((=) {A=~A} {B=~B} ~x ~y) =>
101+ case (headName x, headName y) of
102+ (Just xHd, Just yHd) =>
104+ then fail [ TextPart "Mismatch between", NamePart xHd
105+ , TextPart "and", NamePart yHd
107+ else do fn <- getInjectivity xHd
108+ tyH <- newHole "ty" `(Type)
109+ tmH <- newHole "tm" (Var tyH)
111+ letbind n (Var tyH) (Var tmH)
113+ (_, _, fnTy) <- lookupTyExact fn
115+ ((_, arg) :: _) <- reverse <$> apply (Var fn) (replicate (pred (countBinders fnTy)) (True, 0) ++ [(False,0)])
116+ | _ => fail [TextPart "No hole for argument"]
119+ focus arg; apply tm []; solve
120+ _ => fail [TextPart "oops"]
122+ _ => fail [TextPart "can't use injectivity on non-equality"]