Derive generators on inductives with struct params - #37
Conversation
| -- The field's declared type, read as the codomain of the projection's | ||
| -- signature `∀ (_ : sName ..), fieldType`. Structure fields here are the | ||
| -- metadata-configuration types, whose field types do not depend on the value. | ||
| let projType ← forallTelescopeReducing (← inferType (mkConst projName)) |
There was a problem hiding this comment.
Here, we call mkConst without specifying universe levels -- this is fine for Strata in practice since the parameterized types are all Type 0. However, in the future, if we have types parameterized by universe-polymorphic structures (see example below), the projType would be computed incorrectly. To fix this, we would need to extract the universe levels from ty (the type expression for the structure) and pass them to mkConst. I don't think universe-polymorphic structures are that common in practice, so it's fine to leave it out, but wanted to bring this up just in case.
Here's an example of a universe-polymorphic structure parameter:
-- Universe-polymorphic structure type
structure Config.{v} where
Carrier : Type v
default : Carrier
-- Config.{0} gives Carrier : Type 0, Config.{1} gives Carrier : Type 1
inductive Tree (C : Config.{u}) : Type u where
| leaf : C.Carrier → Tree C
| node : Tree C → Tree C → Tree CThere was a problem hiding this comment.
Rather than try to address this, I left a "Limitation" comment that documents the weakness.
|
Looks generally good to me! Left a few minor comments |
60fa8b9 to
5dfee8e
Compare
- StrataLexprGen: generate non-integer rationals in Arbitrary Rat via mkRat numerator denominator (was Rat.ofInt only). - Utils: simplify isFixedUngenerable's instance probe to a guarded let-bind returning inst.isNone (was a nested match). - Rename 'generatable' -> 'generable': isFixedUngeneratable -> isFixedUngenerable (Utils) and generatableVars -> generableVars (SearchTree). - MakeConstrainedProducerInstance: document the universe-polymorphic structure-parameter limitation of mkConst projName (not supported; rare in practice).
ad94058 to
862613e
Compare
|
Looks great, thanks! |
5dfee8e to
89e0d5c
Compare
- StrataLexprGen: generate non-integer rationals in Arbitrary Rat via mkRat numerator denominator (was Rat.ofInt only). - Utils: simplify isFixedUngenerable's instance probe to a guarded let-bind returning inst.isNone (was a nested match). - Rename 'generatable' -> 'generable': isFixedUngeneratable -> isFixedUngenerable (Utils) and generatableVars -> generableVars (SearchTree). - MakeConstrainedProducerInstance: document the universe-polymorphic structure-parameter limitation of mkConst projName (not supported; rare in practice).
862613e to
b76ef06
Compare
- StrataLexprGen: generate non-integer rationals in Arbitrary Rat via mkRat numerator denominator (was Rat.ofInt only). - Utils: simplify isFixedUngenerable's instance probe to a guarded let-bind returning inst.isNone (was a nested match). - Rename 'generatable' -> 'generable': isFixedUngeneratable -> isFixedUngenerable (Utils) and generatableVars -> generableVars (SearchTree). - MakeConstrainedProducerInstance: document the universe-polymorphic structure-parameter limitation of mkConst projName (not supported; rare in practice).
b76ef06 to
c2e1bbb
Compare
`derive_generator`/`derive_mutual` could not produce values of an inductive parameterized by a *structure* (e.g. Strata's `LExpr T` where `T : LExprParams` carries the metadata/identifier/type-annotation types). The structure parameter `T.mono : LExprParamsT` rides along as an argument of every constructor, and the deriver tried to *generate* it — yielding a `Type 1`-in-`Type` universe error — and had no way to generate the per-constructor metadata fields (`m : T.base.Metadata`). This mirrors the gap that `Specimen.DeriveArbitrary` fixes for the unconstrained `deriving Arbitrary` path via `expandStructBinders`. Three coordinated changes make the fully-parameterized relation derivable: 1. Don't lift fixed, ungeneratable subterms during conclusion flattening (Utils.lean). `collectUnmatchableSubterms` now skips a subterm whose free variables are all fixed inputs *and* whose type has no `Arbitrary` instance (e.g. `T.mono`). Ordinary fixed value subterms like `n * n : Nat` still flatten (they have `Arbitrary`), so checker behavior is unchanged. The fixed-input set is the conclusion's non-output bare-variable arguments (DeriveConstrainedProducer). 2. Emit per-field producer instance binders for structure parameters (MakeConstrainedProducerInstance.lean). New `expandStructInstBinders` / `mkProducerParamInstBinders` mirror `expandStructBinders`: a sort param `α` keeps `[Arbitrary α] [DecidableEq α]`; a structure param `T` expands to `[Arbitrary T.base.Metadata]` … . Threaded through both the single-instance and mutual-`def` emission paths (the latter places struct-field binders innermost, where the value param they reference is in scope). 3. Drop implicit constructor arguments from conclusion outputs (MExp.lean). `dropImplicitCtorArgsExpr` removes implicit-position args of each data constructor in the produced value (e.g. `LExpr.const`'s `T`, `Option.some`'s `α`) so the implicit-allowing emission re-infers them instead of mis-placing them positionally. StrataLexprGen now derives a generator for the genuine `@LExpr.HasTypeA T …` (abstract `T`, no monomorphization) and its embedded `#eval` confirms soundness: 60/60 sampled terms type-check at the requested type. Full test suite green.
Vendor `LExpr.typeCheck` (and its `LMonoTy.isArrow` dependency) verbatim from `Strata/DL/Lambda/Denote/LExprAnnotated.lean` into LambdaCore, and use it in the StrataLexprGen soundness `#eval` in place of the hand-rolled `typeCheckP`. This makes the check authoritative: `LExpr.typeCheck` is the actual Strata checker, proved equivalent to `HasTypeA` upstream. Sampled terms remain 25/25 (and 60/60 across the trial set) well-typed; full suite green.
- StrataLexprGen: generate non-integer rationals in Arbitrary Rat via mkRat numerator denominator (was Rat.ofInt only). - Utils: simplify isFixedUngenerable's instance probe to a guarded let-bind returning inst.isNone (was a nested match). - Rename 'generatable' -> 'generable': isFixedUngeneratable -> isFixedUngenerable (Utils) and generatableVars -> generableVars (SearchTree). - MakeConstrainedProducerInstance: document the universe-polymorphic structure-parameter limitation of mkConst projName (not supported; rare in practice).
c2e1bbb to
111d1b1
Compare
| | .Enumerator => ``Enum | ||
|
|
||
| let arbitraryTypeParamInstances ← mkTypeClassInstanceBinders typeParams #[producerUnconstrainedClass, ``DecidableEq] | ||
| let arbitraryTypeParamInstances0 ← mkTypeClassInstanceBinders typeParams #[producerUnconstrainedClass, ``DecidableEq] |
There was a problem hiding this comment.
One of my PRs modifies the way we track bracketed typeclass instance arguments to only collect those that are truly necessary. It does so by traversing the dependency graph and propagating bottom up the needed dependencies from the schedules. My only concern is how well this change would adapt to that.
|
Canceling this in favor of PR #47 |
Support structure-parameterized output types in the constrained deriver
derive_generator/derive_mutualcould not produce values of an inductive parameterized by a structure (e.g. Strata'sLExpr TwhereT : LExprParamscarries the metadata/identifier/type-annotation types). The structure parameterT.mono : LExprParamsTrides along as an argument of every constructor, and the deriver tried to generate it — yielding aType 1-in-Typeuniverse error — and had no way to generate the per-constructor metadata fields (m : T.base.Metadata). This mirrors the gap thatSpecimen.DeriveArbitraryfixes for the unconstrainedderiving Arbitrarypath viaexpandStructBinders.Three coordinated changes make the fully-parameterized relation derivable:
Don't lift fixed, ungeneratable subterms during conclusion flattening (Utils.lean).
collectUnmatchableSubtermsnow skips a subterm whose free variables are all fixed inputs and whose type has noArbitraryinstance (e.g.T.mono). Ordinary fixed value subterms liken * n : Natstill flatten (they haveArbitrary), so checker behavior is unchanged. The fixed-input set is the conclusion's non-output bare-variable arguments (DeriveConstrainedProducer).Emit per-field producer instance binders for structure parameters (MakeConstrainedProducerInstance.lean). New
expandStructInstBinders/mkProducerParamInstBindersmirrorexpandStructBinders: a sort paramαkeeps[Arbitrary α] [DecidableEq α]; a structure paramTexpands to[Arbitrary T.base.Metadata]… . Threaded through both the single-instance and mutual-defemission paths (the latter places struct-field binders innermost, where the value param they reference is in scope).Drop implicit constructor arguments from conclusion outputs (MExp.lean).
dropImplicitCtorArgsExprremoves implicit-position args of each data constructor in the produced value (e.g.LExpr.const'sT,Option.some'sα) so the implicit-allowing emission re-infers them instead of mis-placing them positionally.StrataLexprGen now derives a generator for the genuine
@LExpr.HasTypeA T …(abstractT, no monomorphization) and its embedded#evalconfirms soundness: 60/60 sampled terms type-check, using the LExpr typechecking algorithm, at the requested type. Full test suite green.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.