@@ -3,13 +3,8 @@
3||| eventual Prelude inclusion.
3||| eventual Prelude inclusion.
4module Pruviloj.Core
4module Pruviloj.Core
7−import Language.Reflection.Elab
8import Language.Reflection.Utils
6import Language.Reflection.Utils
10−data Infer : Type where
11− MkInfer : (a : Type) -> a -> Infer
13||| Run something for effects, throwing away the return value
8||| Run something for effects, throwing away the return value
14ignore : Functor f => f a -> f ()
9ignore : Functor f => f a -> f ()
15ignore x = map (const ()) x
10ignore x = map (const ()) x
@@ -85,11 +80,11 @@ intros = do g <- snd <$> getGoal
86||| Run a tactic inside of a particular hole, if it still exists. If
81||| Run a tactic inside of a particular hole, if it still exists. If
87||| it has been solved, do nothing.
82||| it has been solved, do nothing.
88−inHole : TTName -> Elab () -> Elab ()
83+inHole : TTName -> Elab a -> Elab (Maybe a)
89inHole h todo =
84inHole h todo =
90− when (h `elem` !getHoles) $
85+ if (h `elem` !getHoles)
91− do focus h
86+ then do focus h; Just <$> todo
92− todo
87+ else return Nothing
94||| Restrict a polymorphic type to () for contexts where it doesn't
89||| Restrict a polymorphic type to () for contexts where it doesn't
95||| matter. This is nice for sticking `debug` in a context where
90||| matter. This is nice for sticking `debug` in a context where
@@ -142,3 +137,89 @@ bindPat = do compute
142 case g of
137 case g of
143 Bind n (PVTy _) _ => patbind n
138 Bind n (PVTy _) _ => patbind n
144 _ => fail [TermPart g, TextPart "isn't looking for a pattern."]
139 _ => fail [TermPart g, TextPart "isn't looking for a pattern."]
141+||| The underlying implementation type for the inferType operator.
142+data Infer : Type where
143+ MkInfer : (a : Type) -> a -> Infer
145+||| Run a tactic script in a context where the type of the resulting
146+||| expression must be solvable via unification. Return the term and
149+||| @ tac a tactic script that will be run with focus on the hole
150+||| whose type is to be inferred.
152+inferType : (tac : Elab ()) -> Elab (TT, TT)
154+ case fst !(runElab `(Infer) (startInfer *> tac)) of
155+ `(MkInfer ~ty ~tm) => return (tm, ty)
156+ _ => fail [TextPart "Not infer"]
158+ startInfer : Elab ()
159+ startInfer = do [_, (_, tmH)] <- apply (Var `{MkInfer}) [(True, 0), (False, 1)]
160+ | err => fail [TextPart "Type inference failure"]
164+||| Given one tactic that produces a list of subgoal names and another
165+||| that produces some result, run the second tactic in each hole
166+||| produced by the first and return the resulting values.
168+||| Elab has no built-in notion of "subgoals", so this simulates the
169+||| Coq or JonPRL semicolon operators.
171+||| @ first run this tactic to produce subgoals
172+||| @ after run this tactic in each subgoal
173+andThen : (first : Elab (List TTName)) -> (after : Elab a) -> Elab (List a)
174+andThen first after =
176+ catMaybes <$> for hs (flip inHole after)
178+||| Refine the current goal using some term, constructing holes for
179+||| all arguments that can't be inferred. Return the list of generated
182+||| @ tm the term to apply to some number of goals
183+refine : (tm : Raw) -> Elab (List TTName)
185+ do ty <- (snd <$> check tm) >>= forgetTypes
188+ -- we don't care about negative results because it'll just fail anyway
189+ let argCount = minus (countPi ty) (countPi g)
190+ newHoles <- apply tm (replicate argCount (True, 0))
192+ actualHoles <- getHoles
193+ return (filter (flip elem actualHoles) (map snd newHoles))
195+ where countPi : Raw -> Nat
196+ countPi (RBind _ (Pi _ _) body) = S (countPi body)
200+||| Split a pair into its projections, binding them in the context
201+||| with the supplied names. A special case of Coq's `inversion`.
202+both : Raw -> TTName -> TTName -> Elab ()
204+ do -- We don't know that the term is canonical, so let-bind projections applied to it
205+ (A, B) <- isPairTy (snd !(check tm))
206+ remember n1 A; apply `(fst {a=~A} {b=~B} ~tm) []; solve
207+ remember n2 B; apply `(snd {a=~A} {b=~B} ~tm) []; solve
209+ isPairTy : TT -> Elab (Raw, Raw)
210+ isPairTy `((~A, ~B) : Type) = [| MkPair (forgetTypes A) (forgetTypes B) |]
211+ isPairTy tm = fail [TermPart tm, TextPart "is not a pair"]
213+||| Let-bind all results of completely destructuring nested tuples.
215+||| This makes them available to the `hypothesis` tactic, among others.
217+||| @ tm the nested tuple to destructure
219+unproduct : (tm : Raw) -> Elab ()
221+ do n1 <- gensym "left"
222+ n2 <- gensym "right"
224+ try (unproduct (Var n1))
225+ try (unproduct (Var n2))