Is your feature request related to a problem? Please describe.
The interpreter uses a naive (but perhaps time-efficient) representation of closures, which is to represent the entire scope using a singly linked "immutable" list of Envs, each representing a "level" of scope, starting with the innermost, so that the outermost scopes can be shared. (Only benign, idempotent mutation happens, from thunk to proper value)
This works, but it means that a closure needs to hold a reference to the entire scope, even though only specific variables in that scope will ever be accessed. This leads to unnecessary space leaks: whenever an expression returns a thunk, all other variables in that scope are retained until all such thunks have been evaluated successfully.
We already have individually collectable thunks. Env just happens to point to all of them, and our thunk point to the Envs.
Describe the solution you'd like
An alternative implementation could:
- Have two
ExprVar lookup strategies.
- the current strategy for large sets of free variables, which would be "too big to copy". Example:
rec { ..... } scopes.
- a new copying strategy which performs a lookup in a small flattened closure of up to an experimentally determined number of variables
- During parsing, maintain the set of free variables for each node.
- During scope checking (bindVars), decide which closure type to use, save that decision, and save the appropriate index in
ExprVar. The set of free variables may be cleared to release any extra memory that was used.
Describe alternatives you've considered
Status quo is simple and possibly time efficient for small expressions.
An oversized heap does incur recurring time losses though, due to slower GC!
Additional context
This would be an experiment that may fail to produce a positive result.
Priorities
Add 👍 to issues you find important.
Is your feature request related to a problem? Please describe.
The interpreter uses a naive (but perhaps time-efficient) representation of closures, which is to represent the entire scope using a singly linked "immutable" list of
Envs, each representing a "level" of scope, starting with the innermost, so that the outermost scopes can be shared. (Only benign, idempotent mutation happens, from thunk to proper value)This works, but it means that a closure needs to hold a reference to the entire scope, even though only specific variables in that scope will ever be accessed. This leads to unnecessary space leaks: whenever an expression returns a thunk, all other variables in that scope are retained until all such thunks have been evaluated successfully.
We already have individually collectable thunks.
Envjust happens to point to all of them, and our thunk point to theEnvs.Describe the solution you'd like
An alternative implementation could:
ExprVarlookup strategies.rec { ..... }scopes.ExprVar. The set of free variables may be cleared to release any extra memory that was used.Describe alternatives you've considered
Status quo is simple and possibly time efficient for small expressions.
An oversized heap does incur recurring time losses though, due to slower GC!
Additional context
This would be an experiment that may fail to produce a positive result.
Priorities
Add 👍 to issues you find important.