5 ms·
In a language with algebraic effects, questions like "how should I make this `CancellationToken` available to these forty small functions?" simply go away :-)
by fleabitdev 2y ago
In a language with algebraic effects, questions like "how should I make this `CancellationToken` available to these forty small functions?" simply go away :-)
It's ambient state, just like a `catch` block, and so you can make it ambiently available to a whole tree of function calls. The outcome is the same as passing around a context argument by hand, and it can have equally strong type-checking, but the compiler handles all of the boilerplate for you.
To answer your second question: I agree that, in a dynamic language like JavaScript, making all of these language features implicit could be too costly. I'm more optimistic about effect systems in statically-typed languages.
- magicalhippo 2y ago> ambiently available to a whole tree of function calls So a "localized global variable" of sorts? Sounds interesting, got any links to examples I could look at?
- fleabitdev 2y agoThe term is "dynamic scope": https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexic... It isn't a very common language feature, but you could take a look at React's `Context` or Common Lisp's `defparameter`.
- magicalhippo 2y agoAh, like Python objects then. Which is unfortunate, because that's one of my main dislikes with languages like Python. I was imagining more along the lines of (on-the-spot pseudo-code) using [x := foo(...)] { bar(); output(); } func bar() { x = x + 1 } where bar() and output(), or something they call in turn, can reference x and it would be a compile-time error to use bar() or output() in cases where they couldn't resolve x. Or something more along those lines. Anyway, cheers, always fun to ponder these things.
- fleabitdev 2y agoSorry, the Wikipedia article isn't very helpful. Your example is the correct one. The killer feature is that you can shadow a dynamic variable, changing its value for the duration of a dynamic scope, in the same way that an inner `catch` handler overrides an outer one. For example, you could have a dynamic variable which tells the `print` function where to send its text output. The variable's value would probably default to stdout. By temporarily assigning a string-stream to that variable, you could collect an arbitrary function's text output into a string instead. Regardless of where the text is going, any function which produces text could still use the convenient global `print` function.
- magicalhippo 2y agoRight. The closest thing I'm familiar with is the dynamic context used in Serilog[1], where you add log properties to the current scope, which gets added to each log line generated in that scope, and removed once the scope exits. Of course, no compile-time checking there, so the combination sounds indeed quite useful. https://github.com/serilog/serilog/wiki/Enrichment#the-logcontext https://github.com/serilog/serilog/wiki/Enrichment#the-logco...