Repository navigation
A bound index is not a free variable (#1019) - #1045
Merged
Merged
Conversation
FreeVariables knew about Lambda and the set builder and about no other binder.
A summation and a product bind their index, so sum(k, k, 1, n) is a function of
n alone, and a definite integral binds its variable between its limits. All
three reported the bound name as free.
The index is bound over the bounds as well as the body, which is what Binding
already says of itself -- the name a binder is handed is honoured throughout
it, through the summand and the bounds -- so sum(k, k, k, n) is { n } as well.
An indefinite integral and a derivative are left alone, and that is the part
worth pinning rather than the part worth fixing. The antiderivative of t * b
over t is b * t ^ 2 / 2 + C, still a function of t, and d/dt denotes a function
of t. They look like the same shape as a summation and are not; a sweep that
completes the binder list by adding them makes them wrong, so a test says so.
Vars and VarsAndConsts are untouched. They mean every name occurring, bound
ones included, which is what their own XML example has always documented by
listing a lambda's parameter under variables and constants.
Measured on a build of each side; 8070 -> 8080 passed, 0 failed, and no
existing test depended on the old answers.
This was referenced Aug 27, 2026
Closed
Rafael-SOWNet
added a commit
that referenced
this pull request
Aug 27, 2026
`FreeVariables` learned about a summation, a product and a definite integral in #1045, and about `limit` not at all. That commit enumerates the indefinite integral and the derivative as deliberate exclusions and does not mention a limit, so this was an omission rather than a decision. And the reason those two are excluded is what makes this one bind. An antiderivative of `t * b` over `t` is `b * t ^ 2 / 2 + C` and `d/dt` denotes a function of `t` -- both are still functions of the variable. **A limit never is.** `lim(t, t, 0)` is 0, and no limit's value depends on the name it approaches along, so the variable is consumed exactly as a summation index is. The destination is where the dependence goes and is bound over as well, so `lim(t, t, b)` is a function of `b` alone. `Limitf` is a `CalculusOperator(Expression, Var)`, the same shape as `Integralf`, so this is one arm next to it -- unconditional where the integral's is conditional, which is the distinction the comment now records. Measured on a build of each side: `limit(t * b, t, 0).FreeVariables` was `{ t, b }` and is `{ b }`. `Vars` and `VarsAndConsts` untouched.
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.
FreeVariablesknew about two binders —Lambdaand the set builder — and about no others. Asummation and a product bind their index, and a definite integral binds its variable between its
limits. All three reported the bound name as free.
Measured on a build of 2.3.0 and a build of this branch:
sum(k, k, 1, n){ k, n }{ n }kis a function ofnaloneproduct(k, k, 1, n){ k, n }{ n }integral(t * b, t, 0, 1){ b, t }{ b }tintegral(t * b, t){ b, t }{ b, t }derivative(t * b, t){ b, t }{ b, t }lambda(x, x + y){ y }{ y }{ k : k > a }{ a }{ a }The unchanged rows are the interesting part
An indefinite integral does not bind: the antiderivative of
t * bovertisb * t ^ 2 / 2 + C, still a function oft. Nor does a derivative —d/dtdenotes a function oft. They look like the same shape as a summation and are not, and a later sweep that "completes"the binder list by adding them would make them wrong.
AnIndefiniteIntegralAndADerivativeDoNotBindpins that, with the reason in the test.
Scope of the binding
The index is bound over the bounds as well as the body, so
sum(k, k, k, n)is{ n }. That isnot a new decision —
Bindingalready says of itself that thename a binder is handed "is honoured throughout it, through the summand and the bounds", and this
follows it rather than inventing a second answer.
VarsandVarsAndConstsare untouchedThey mean every name occurring, bound ones included:
"sum(k, k, 1, n)".ToEntity().Varsis still{ k, n }. That is what their own XML example has always documented — it lists a lambda's parameterunder variables and constants. Occurring and free are different questions and the three properties
answer them separately. This corrects item 2 of #1019, which claimed
VarsAndConstswas wrong forlambda; it is not, and this is a one-property change rather than a three-property one.Why this does not wait for a major version
#1019's own criterion is that a change belongs on the pending-breakages list when it moves the value
of existing input as a deliberate convention choice. This is a wrong answer becoming a right one —
a bound index was never free — which the same paragraph says has gone in a minor before.
Verification
FreeVariablesTest.cs, which already held theLambdaand set-buildercases from FreeVariables leaks a set builder's %1 placeholder, and only a lambda counts as a binder #989, so the binder story is in one place.
master.Exactly the cases added; no existing test depended on the old answers.
BREAKING-CHANGES.mdentry with both values measured on a build of each side.Answers Happypig375's question on #1019 — "identify the correct design here" — with the measurement
posted there.