Commit Graph

2 Commits

Author SHA1 Message Date
Scott Olsen
816eb65474
fix: allow dynamic closures to mutate the global env (#1184) 2021-03-09 23:30:49 +01:00
Scott Olsen
381fa0f179
fix: Closure context (#1124)
* feat: add semigroup instance for Env and Context

Adds a semigroup instance for combining Envs and Contexts--this will be
necessary to ensure closure's are evaluated under the combination of the
context captured in the closure and the current global context during
evaluation.

The semigroup instances are left biased and will prefer bindings defined
in the left context/env argument in the case of conflicts (this is in
keeping with the implementation of `union` in Data.Map, the underlying
function powering this instance).

* fix: evaluate closures under the current context

Previously, closures were evaluated only under the context that was
stored during their creation. However, this can lead to issues where
closures do not resolve bindings to their latest definitions.

This commit leverages the semigroup instance of Context to evaluate
closures under the combination of the context captured during their
creation and the broader context during their evaluation/application,
preferring the context captured in the closure when bindings conflict.

This ensures that when we apply closures their local bindings still
resolve to definitions encapsulated in the closure, while other bindings
resolve to the definitions contained in the current overarching context
(instead of the old context captured by the closure).

* fix: fix bias for context env combinations in semigroup

Previously, the semigroup instance for Context was left-biased in all
the combinations of each context's environment. However, one usually
calls this function to combine some older context with a newer context,
intending to have the older context win *only* in the case of internal
environments.

This commit changes the behavior of the semigroup instance to better
reflect this use case. When one calls:

`c <> c'`

The envs in each context are combined as follows:

- internal: If conflicts occur, prefer the bindings of the context on
  the LHS (the "older" context)
- global: If conflicts occur, prefer the bindings of the context on the
  RHS ("newer" context)
- type: If conflicts occur, prefer the bindings of the context on the
  RHS ("newer" context)

This ensures the resulting context uses the latest values in the chance
of conflicts in the global env/type env, and the older values in the
case of an internal env (a closure).

* test: add basic tests for closures

* refactor: rename test/closure -> test/dynamic-closure

Also updates the forms to test dynamic closures.
2021-01-12 22:28:51 +01:00