Repository navigation
A lambda is written with an arrow as well as a call (#495) - #1151
Merged
Merged
Conversation
`a => a + 3` was a parse error and is now the same entity as `lambda(a, a + 3)`. Several parameters are the curried form #495's plan specifies: `a b => a + b` is `a => b => a + b`, which is `lambda(a, b, a + b)`. The nodes were never missing. `Lambda`, `Application`, beta reduction and currying are all in the library already, and #1137's ODE solver is built on them; what that plan describes and the library did not have is the syntax. This is the half of it that costs nothing -- `=` followed by `>` was not a token and not a parse, so no reading of any valid input changes. The other half (`f a b`, `sin x`, `sin (x)`) changes what juxtaposition means, which is the decision #286 is about, and is not free. Written by sharing the left side rather than as `names+ '=>' body | expression`. Both alternatives of that begin with a name and stay viable through a second one, juxtaposition being multiplication, so `a b => a + b` was decided as a product before the arrow was reached and came back "mismatched input '=>'". Sharing leaves one decision, taken on the token after the left side, and the parameters are read back out of the product it parsed as. That also settles the parameter that cannot arrive as a name token: `i` lexes as the imaginary unit, so `i => i + 1` had to be read the way `lambda(i, i + 1)` is read -- through `Binding` -- and the two now agree. #976. A parameter that is not a name is refused, as the plan says: `a 3 => 3`, `2 => 3` and `x + 1 => 2` raise. They raised before too, under a different name -- `UnhandledParseException` where they now raise `InvalidArgumentParseException` -- which is recorded in BREAKING-CHANGES. The arrow is read, not printed. A lambda still prints as `lambda(x, x + 1)`, which is what keeps the round trip the printed form promises. The grammar was regenerated the way ImproveParser.md sets out. The unmodified grammar was regenerated first and its diff confirmed empty, so what is committed here is the rule and not a toolchain version. Syntax.md updated in three places. Full suite 9386 passed, 0 failed. Part of #495. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
# Conflicts: # Sources/.editorconfig
# Conflicts: # Sources/.editorconfig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
a => a + 3was a parse error. It is now the same entity aslambda(a, a + 3), and severalparameters are the curried form #495's plan specifies.
The nodes were never missing
Lambda,Application, beta reduction and currying are all already in the library — #1137's ODEsolver is built on them, and
apply(apply(lambda(x, lambda(y, x + y)), 1), 2)has simplified to3throughout. What the plan describes and the library did not have is the syntax.This is the half of that syntax which costs nothing:
=followed by>was not a token and not aparse, so no reading of any valid input changes. The other half —
f a bforapply(apply(f, a), b),sin xwithout brackets,sin (x)with a space — changes whatjuxtaposition means. That is the same decision #286 is about, it is a real compatibility break,
and it is not in here.
Two things that had to be got right
The grammar is left-factored, and that is not a style choice. Written the obvious way —
— both alternatives begin with a name and stay viable through a second one, juxtaposition being
multiplication. So
a b => a + bwas decided as a product before the arrow was ever reached, andcame back
mismatched input '=>' expecting <EOF>. Sharing the left side leaves one decision,taken on the token after it, and the parameters are read back out of the product it parsed as.
icannot arrive as a name token. It lexes as the imaginary unit, so a rule matchingVARIABLEtokens could never accepti => i + 1— whilelambda(i, i + 1)has always worked,because the call form reads its parameters through
Binding(#976). The left-factored form getsthis for free by doing the same, and the two spellings now agree. Asserted.
What is refused, and what is untouched
Every parameter must be a name, which is what the plan says:
a 3 => 32 => 3,x + 1 => 2,sin(x) => 2Those raised before too, as
UnhandledParseException; they now raiseInvalidArgumentParseException. Still invalid, differently named — recorded inBREAKING-CHANGES.md, since code catching by type will not catch the new one.Untouched, and pinned by tests:
>=,<=,>,<,=,->(implication, not a lambdaarrow),
a bas multiplication,x2as a power.The arrow is read, not printed. A lambda still prints as
lambda(x, x + 1), which is whatkeeps the round trip the printed form promises: several spellings may be read, exactly one is
printed. Asserted, including that the printed form reads back equal.
On regenerating the parser
Done the way
ImproveParser.mdsets out. PerAGENTS.md, I regenerated the unmodified grammarfirst and confirmed its diff was empty — it was, once the post-processor had run — so what is
committed here is the rule and not a toolchain version.
Syntax.mdis updated in three places: the round-trip contract, the structural-node list, andthe line that says
->is not a lambda arrow.Verification
Full suite 9386 passed, 0 failed, 14 skipped. 30 new tests, each asserting the arrow form
against its
lambda(...)spelling rather than against a printed string — the point being that thetwo produce the same entity.
Part of #495 — the rest of that plan's syntax is the juxtaposition change, deliberately not here.