Kernel is very interesting. It has fexpr-like combiners (operatives) which implicitly receive a reference to the dynamic environment of their caller. The environments are first-class and modelled as a DAG, with the local bindings in the root node with a list of other parent environments. The list of parents, and any bindings in the parent environments cannot be modified, but only the local bindings can. This puts constrains the operatives a bit - they can't just mutate anything in the dynamic environment, but only the local bindings of an environment for which they have a direct reference.
Additionally, Kernel has dynamic binding built-in, and done in a nice way. You never explicitly access a dynamic variable but you only have an accessor function to it. A new scope is created when binding a dynamic variable, and the accessor will return whatever was bound anywhere in the dynamic extent of this scope.
($define! (with-str get-str) (make-keyed-dynamic-variable))
($define! f
($lambda ()
(print (get-str))))
(with-str "Hello, world!"
($lambda ()
(f)
(with-str "Goodbye, world!" f)
(f)))
Prints "Hello, world!" "Goodbye, world!" "Hello, world!"Perhaps the only downside to this is that a runtime error will be raised if `get-str` is called before a value is bound. I think it would be a bit nicer to include a default binding as an argument to the call of `make-keyed-dynamic-variable`.