choose operator in Boole#1365
Conversation
joscoh
left a comment
There was a problem hiding this comment.
Could you explain why we need separate syntax for functions defined by choose and why we can't use use an inlined function with the existing choose expressions?
There was a problem hiding this comment.
Should this be in FeatureRequests or just regular tests?
There was a problem hiding this comment.
Merged into choose_operator.lean (which is already imported by StrataBooleTest.lean).
The file wasn't imported before, so its tests weren't running.
|
|
||
| procedure test_choose_fn(x: int) returns (w: int) | ||
| spec { | ||
| requires ∃ z: int :: good(z, x); |
There was a problem hiding this comment.
It would be good to see the failing/unknown result if this precondition is omitted.
There was a problem hiding this comment.
Added chooseFnNoPrecondSeed — without the precondition the ensures still passes,
because the axiom unconditionally asserts good(best(x), x). Comment explains this.
| | matchChoose3 -- matched 'cho' | ||
| | matchChoose4 -- matched 'choo' | ||
| | matchChoose5 -- matched 'choos' | ||
| | afterChoose -- matched 'choose', awaiting whitespace to confirm keyword boundary |
There was a problem hiding this comment.
I know this is ultimately a style preference, and maybe there are other considerations, but I would rather just use \epsilon to avoid this hardcoded 5-character matching. Then choose can be handled exactly like quantifiers.
There was a problem hiding this comment.
Done, thanks! I replaced the 5-state machine with a single ch == 'ε' check alongside ∀/∃.
Updated Grammar.lean surface syntax and all test programs accordingly.
| | .command_choosefndef _ ⟨_, n⟩ ⟨_, targs?⟩ bs ret v pred => | ||
| -- `function f(params) : R := choose z :: pred(z, params)` | ||
| -- Emits: uninterpreted function declaration + axiom | ||
| -- ∀ p1:T1,...,pn:Tn, ∀ z:Tz, (z = f(p1,...,pn)) → pred(z, p1,...,pn) |
There was a problem hiding this comment.
Why don't you need an assumption that pred is inhabited?
There was a problem hiding this comment.
Added a comment: unlike w := ε z . pred (which guards with an existence assertion),
the function form emits the axiom unconditionally. Soundness requires the caller to
guarantee inhabitation, e.g. via requires ∃ z . pred(z, params).
There was a problem hiding this comment.
I don't quite understand this. When you say "Soundness requires the caller to
guarantee inhabitation", is there anything enforcing this or is it up to the user to make sure they don't declare unsound function definitions. In the latter case, how is this better than just writing an axiom directly?
There was a problem hiding this comment.
Nothing enforces it. You're right that it's essentially syntactic sugar for:
function f(params) : R; -- uninterpreted
axiom ∀ params, pred(f(params), params);
The benefit over writing those two lines directly is just convenience. Soundness is the user's responsibility exactly as with axiom. We could require a proof obligation ∃ z . pred(z, params) at the declaration site, but that would need quantifier alternation (∀ params, ∃ z . pred) which is harder to discharge automatically. For now the design mirrors Verus spec functions, where choose-based definitions are also trusted by convention.
Summary
choose-function declarations (
command_choosefndef)Introduces
function f(params) : R := choose z : T . pred(z, params);as afirst-class Boole construct for defining functions by a property rather than an
implementation — similar to Verus spec
choose.Lowering (in
StrataBoole/Verify.lean):f.∀ p1:T1, …, ∀ pn:Tn, ∀ z:Tz, (z = f(p1,…,pn)) → pred(z,p1,…,pn)The 3-forall form avoids de Bruijn index shifting:
pred's natural bvar indices(0 = z, 1 = pn, …, n = p1) match the quantifier nesting exactly.
DDM scope chain:
@[scope(b)] v+@[scope(v)] predgivespredtransitiveaccess to all parameters via
resultContextchaining.Dot separator for
chooseExtends
normalizeUnicodeQuantifierSeparators(and its byte-position companionnormalizedQuantifierSepStep) inStrataDDM/Elab.leanto recognise the keywordchooseas a binder, rewritingchoose z : T . pred→choose z : T :: predbefore DDM parsing. Mirrors the existing
∀/∃dot normalization.Both
choose_assignandcommand_choosefndefnow accept.or::.Files changed
StrataDDM/StrataDDM/Elab.lean— state-machine extension forchoosekeywordStrataBoole/StrataBoole/Grammar.lean— newcommand_choosefndefopStrataBoole/StrataBoole/Verify.lean— lowering forcommand_choosefndefStrataBooleTest/FeatureRequests/choose_fn.lean— new testStrataBooleTest/FeatureRequests/choose_operator.lean— updated to.syntax