@@ -927,76 +927,84 @@ where doRealize (inductName : Name) := do
927927 -- to make sure that `target` indeed the last parameter
928928 let e := info.value
929929 let e ← lambdaTelescope e fun params body => do
930- if body.isAppOfArity ``WellFounded.fix 5 then
930+ if body.isAppOfArity ``WellFounded.fix 5 || body.isAppOfArity ``WellFounded.Nat.fix 4 then
931931 forallBoundedTelescope (← inferType body) (some 1 ) fun xs _ => do
932932 unless xs.size = 1 do
933933 throwError "functional induction: Failed to eta-expand{indentExpr e}"
934934 mkLambdaFVars (params ++ xs) (mkAppN body xs)
935935 else
936936 pure e
937937 let (e', paramMask) ← lambdaTelescope e fun params funBody => MatcherApp.withUserNames params varNames do
938- match_expr funBody with
939- |
[email protected] α _motive rel wf body target =>
940- unless params.back! == target do
941- throwError "functional induction: expected the target as last parameter{indentExpr e}"
942- let fixedParamPerms := params.pop
943- let motiveType ←
944- if unfolding then
945- withLocalDeclD `r (← instantiateForall info.type params) fun r =>
946- mkForallFVars #[target, r] (.sort 0 )
938+ unless funBody.isApp && funBody.appFn!.isApp do
939+ throwError "functional induction: unexpected body {funBody}"
940+ let body := funBody.appFn!.appArg!
941+ let target := funBody.appArg!
942+ unless params.back! == target do
943+ throwError "functional induction: expected the target as last parameter{indentExpr e}"
944+ let fixedParamPerms := params.pop
945+ let motiveType ←
946+ if unfolding then
947+ withLocalDeclD `r (← instantiateForall info.type params) fun r =>
948+ mkForallFVars #[target, r] (.sort 0 )
949+ else
950+ mkForallFVars #[target] (.sort 0 )
951+ withLocalDeclD `motive motiveType fun motive => do
952+ let fn := mkAppN (← mkConstWithLevelParams name) fixedParamPerms
953+ let isRecCall : Expr → Option Expr := fun e =>
954+ e.withApp fun f xs =>
955+ if f.isFVarOf motive.fvarId! && xs.size > 0 then
956+ mkApp fn xs[0 ]!
947957 else
948- mkForallFVars #[target] (.sort 0 )
949- withLocalDeclD `motive motiveType fun motive => do
950- let fn := mkAppN (← mkConstWithLevelParams name) fixedParamPerms
951- let isRecCall : Expr → Option Expr := fun e =>
952- e.withApp fun f xs =>
953- if f.isFVarOf motive.fvarId! && xs.size > 0 then
954- mkApp fn xs[0 ]!
955- else
956- none
958+ none
957959
958- let motiveArg ←
959- if unfolding then
960- let motiveArg := mkApp2 motive target (mkAppN (← mkConstWithLevelParams name) params)
961- mkLambdaFVars #[target] motiveArg
960+ let motiveArg ←
961+ if unfolding then
962+ let motiveArg := mkApp2 motive target (mkAppN (← mkConstWithLevelParams name) params)
963+ mkLambdaFVars #[target] motiveArg
964+ else
965+ pure motive
966+
967+ let e' ← match_expr funBody with
968+ |
[email protected] α _motive rel wf _body _target =>
969+ let e' := .const ``WellFounded.fix [fix.constLevels![0 ]!, levelZero]
970+ pure <| mkApp4 e' α motiveArg rel wf
971+ |
[email protected] α _motive measure _body _target =>
972+ let e' := .const `WellFounded.Nat.fix [fix.constLevels![0 ]!, levelZero]
973+ pure <| mkApp3 e' α motiveArg measure
974+ | _ =>
975+ if funBody.isAppOf ``WellFounded.fix || funBody.isAppOf `WellFounded.Nat.Fix then
976+ throwError "Function {name} defined via WellFounded.fix with unexpected arity {funBody.getAppNumArgs}:{indentExpr funBody}"
962977 else
963- pure motive
964- let e' := .const ``WellFounded.fix [fix.constLevels![0 ]!, levelZero]
965- let e' := mkApp4 e' α motiveArg rel wf
966- check e'
967- let (body', mvars) ← M2.run do
968- forallTelescope (← inferType e').bindingDomain! fun xs goal => do
969- if xs.size ≠ 2 then
970- throwError "expected recursor argument to take 2 parameters, got {xs}" else
971- let targets : Array Expr := xs[*...1 ]
972- let genIH := xs[1 ]!
973- let extraParams := xs[2 ...*]
974- -- open body with the same arg
975- let body ← instantiateLambda body targets
976- lambdaTelescope1 body fun oldIH body => do
977- let body ← instantiateLambda body extraParams
978- let body' ← withRewrittenMotiveArg goal (rwFun #[name]) fun goal => do
979- buildInductionBody #[oldIH, genIH.fvarId!] #[] goal oldIH genIH.fvarId! isRecCall body
980- if body'.containsFVar oldIH then
981- throwError m!"Did not fully eliminate `{mkFVar oldIH}` from induction principle body:{indentExpr body}"
982- mkLambdaFVars (targets.push genIH) (← mkLambdaFVars extraParams body')
983- let e' := mkApp2 e' body' target
984- let e' ← mkLambdaFVars #[target] e'
985- let e' ← abstractIndependentMVars mvars (← motive.fvarId!.getDecl).index e'
986- let e' ← mkLambdaFVars #[motive] e'
987-
988- -- We used to pass (usedOnly := false) below in the hope that the types of the
989- -- induction principle match the type of the function better.
990- -- But this leads to avoidable parameters that make functional induction strictly less
991- -- useful (e.g. when the unused parameter mentions bound variables in the users' goal)
992- let (paramMask, e') ← mkLambdaFVarsMasked fixedParamPerms e'
993- let e' ← instantiateMVars e'
994- return (e', paramMask)
995- | _ =>
996- if funBody.isAppOf ``WellFounded.fix then
997- throwError "Function `{name}` defined via `{.ofConstName ``WellFounded.fix}` with unexpected arity {funBody.getAppNumArgs}:{indentExpr funBody}"
998- else
999- throwError "Function `{name}` not defined via `{.ofConstName ``WellFounded.fix}`:{indentExpr funBody}"
978+ throwError "Function {name} not defined via WellFounded.fix:{indentExpr funBody}"
979+ check e'
980+ let (body', mvars) ← M2.run do
981+ forallTelescope (← inferType e').bindingDomain! fun xs goal => do
982+ if xs.size ≠ 2 then
983+ throwError "expected recursor argument to take 2 parameters, got {xs}" else
984+ let targets : Array Expr := xs[*...1 ]
985+ let genIH := xs[1 ]!
986+ let extraParams := xs[2 ...*]
987+ -- open body with the same arg
988+ let body ← instantiateLambda body targets
989+ lambdaTelescope1 body fun oldIH body => do
990+ let body ← instantiateLambda body extraParams
991+ let body' ← withRewrittenMotiveArg goal (rwFun #[name]) fun goal => do
992+ buildInductionBody #[oldIH, genIH.fvarId!] #[] goal oldIH genIH.fvarId! isRecCall body
993+ if body'.containsFVar oldIH then
994+ throwError m!"Did not fully eliminate `{mkFVar oldIH}` from induction principle body:{indentExpr body}"
995+ mkLambdaFVars (targets.push genIH) (← mkLambdaFVars extraParams body')
996+ let e' := mkApp2 e' body' target
997+ let e' ← mkLambdaFVars #[target] e'
998+ let e' ← abstractIndependentMVars mvars (← motive.fvarId!.getDecl).index e'
999+ let e' ← mkLambdaFVars #[motive] e'
1000+
1001+ -- We used to pass (usedOnly := false) below in the hope that the types of the
1002+ -- induction principle match the type of the function better.
1003+ -- But this leads to avoidable parameters that make functional induction strictly less
1004+ -- useful (e.g. when the unused parameter mentions bound variables in the users' goal)
1005+ let (paramMask, e') ← mkLambdaFVarsMasked fixedParamPerms e'
1006+ let e' ← instantiateMVars e'
1007+ return (e', paramMask)
10001008
10011009 unless (← isTypeCorrect e') do
10021010 logError m!"failed to derive a type-correct induction principle:{indentExpr e'}"
0 commit comments