ProCreations's picture
Publish validated ICML reproduction
6c3fe2a verified
Raw
History Blame Contribute Delete
3.86 kB
import Lean
import Mathlib
open Lean Elab Command Term Meta Tactic
set_option autoImplicit false
set_option relaxedAutoImplicit false
structure ProblemSol {Ξ± : Type} (P : Ξ± β†’ Prop) where
Answer : Ξ±
Proof : P Answer
def ProblemTarget (p : Prop) : Prop := p
def getRawBody (e : Expr) (i : Nat := 2) : MetaM Expr := do
lambdaTelescope e fun args body => do
let body ← whnf body
if body.isAppOf ``ProblemSol.mk then
let val := body.getAppArgs[i]!
mkLambdaFVars args val
else
throwError "Extraction failed: Body is not a ProblemSol constructor. Body: {body}"
elab "extract_ans_type " id:ident : term => do
let name ← resolveGlobalConstNoOverload id
let info ← getConstInfoDefn name
getRawBody info.value 0
elab "extract_predicate " id:ident : term => do
let name ← resolveGlobalConstNoOverload id
let info ← getConstInfoDefn name
getRawBody info.value 1
elab "extract_answer " id:ident : term => do
let name ← resolveGlobalConstNoOverload id
let info ← getConstInfoDefn name
getRawBody info.value 2
elab "extract_proof " id:ident : term => do
let name ← resolveGlobalConstNoOverload id
let info ← getConstInfoDefn name
getRawBody info.value 3
namespace FPS
scoped syntax (name := problemSyntax)
"problem" ident bracketedBinder* "find" "(" ident ":" term ")"
"s.t." bracketedBinder* ":" term ":=" term : command
scoped macro_rules
| `(problem $name:ident $vars* find ($ansId:ident : $ansType:term) s.t. $hyps* : $concl:term := $body:term) => do
let proofSpec ← `(fun $ansId:ident : $ansType => βˆ€ $hyps*, ProblemTarget $concl)
`(@[reducible] noncomputable def $name $vars* : ProblemSol $proofSpec := $body)
scoped syntax (name := solveSyntax) "solve" (ppSpace tacticSeq)? : term
@[term_elab solveSyntax]
def elabSolve : TermElab := fun stx expectedType? => do
let some expectedType := expectedType?
| throwError "`solve` must be used in a position of known type"
let mvar ← mkFreshExprMVar expectedType
let mvarId := mvar.mvarId!
let setupTx ← `(tactic|
apply ProblemSol.mk;
intros;
unfold ProblemTarget
)
let _ ← Lean.Elab.Tactic.run mvarId do
withOptions (fun o => o.setBool `tactic.hygienic false) do
evalTactic setupTx
withTacticInfoContext stx[0] (pure ())
if let some seq := stx[1].getOptional? then
evalTactic seq
return mvar
end FPS
namespace DFPS
scoped syntax (name := problemSyntax)
"problem" ident bracketedBinder* "find_all" "(" ident ":" term ")"
"iff" bracketedBinder* ":" term ":=" term : command
scoped macro_rules
| `(problem $name:ident $vars* find_all ($ansId:ident : $ansType:term) iff $hyps* : $concl:term := $body:term) => do
let proofSpec ← `(fun answer_predicate : Prop => βˆ€ $hyps*, (ProblemTarget $concl) ↔ (answer_predicate))
`(@[reducible] noncomputable def $name $vars* ($ansId : $ansType) : ProblemSol $proofSpec := $body)
scoped syntax (name := solveSyntax) "solve" (ppSpace tacticSeq)? : term
@[term_elab solveSyntax]
def elabSolve : TermElab := fun stx expectedType? => do
let some expectedType := expectedType?
| throwError "`solve` must be used in a position of known type"
let hAnswerName := mkIdent `_h_answer
let hConclusionName := mkIdent `_h_conclusion
let mvar ← mkFreshExprMVar expectedType
let mvarId := mvar.mvarId!
let setupTx ← `(tactic|
apply ProblemSol.mk;
intros;
unfold ProblemTarget;
refine @Iff.intro ?_ _ ?Forward ?Backward;
rotate_left;
intros $hAnswerName;
rotate_right;
intros $hConclusionName;
)
let _ ← Lean.Elab.Tactic.run mvarId do
withOptions (fun o => o.setBool `tactic.hygienic false) do
evalTactic setupTx
withTacticInfoContext stx[0] (pure ())
if let some seq := stx[1].getOptional? then
evalTactic seq
return mvar
end DFPS