by psibi on 11/22/20, 3:56 PM with 94 comments
by siraben on 11/22/20, 4:20 PM
- purely functional model of computation and its pitfalls
- Actor model, effectful programming with requests and responses and an implementation in Haskell.
- denotational semantics and combining effects. Once you have a model of your language, what if you want to extend it by adding another effect? It forces you to rewrite the semantics (and thus any interpreter of your language) completely. Taking using the effects-as-requests viewpoint, only the request and handler for an effect needs to be added or changed, and the rest untouched. This is known as "stable denotations".
- really evaluating what it means for an expression to be pure or effectful. Even variable reference should be considered an effect.
- different scoping rules in lambda calculus can be expressed in terms of effects! Creating a dynamic closure is not effectful, though applying it usually is, OTOH, creating a lexical closure is effectful but using it is not.
I think Haskell provides a good example of how a purely functional language can still express effectful computation. through a monadic interface. Though monad transformers have their share of problems when heavily nested (n^2 instances, performance), various effect system libraries are gaining traction.[2] On the bleeding edge of research there's languages like Frank[1] where the effect system is pervasive throughout the language.
[0] https://www.youtube.com/watch?v=GhERMBT7u4w
[1] https://github.com/frank-lang/frank
[2] Implementing free monads from scratch, https://siraben.github.io/2020/02/20/free-monads.html
by skybrian on 11/22/20, 5:19 PM
In a practical system, when writing a library and especially an abstract interface, you’d want to be careful what you promise and declare effects that you might need (but currently don’t use), just in case you will need them later.
It’s not that easy even to distinguish functions that can fail from those that can’t, if you’re trying to anticipate how a system will evolve. Something that’s in-memory now might change to being done over the network later.
by ianbicking on 11/22/20, 6:34 PM
The idea of a dynamic return is just to give a formal way to accumulate things during a set of function calls, without having every function to be aware of what might be happening. In Python context managers are often used for this (e.g., contextlib.redirect_stdout to capture stdout), but thinking about it as another kind of return value instead of "capturing" would be an improvement IMHO. (You have to "capture" when hardcoded imperative code later needs to be retrofitted, but as it is retrofitting is all we have.)
But dynamic returns aren't quite like an effect system unless you also create something more-or-less like a transaction or a changeset. We usually think about transactions as simply a way to rollback in case of an error, but as a changeset there's all kinds of interesting auditing and logging and debugging possibilities. E.g., if your effect is writing to stdout, you could rewrite all those changes (e.g., apply a filter, or add a text prefix to each line).
by aozgaa on 11/22/20, 6:42 PM
I believe the typesetting tool Madoko[1] is implemented in Koka, though in fairness Daan Leijen developed both Koka and Madoko.
by toolslive on 11/22/20, 11:55 PM
by klodolph on 11/22/20, 10:21 PM
by dustingetz on 11/23/20, 12:27 AM
by smegma2 on 11/22/20, 6:24 PM
fun addRefs(
a : forall<h> ref<h,int>,
b : forall<h> ref<h,int>
) : total ()
{
a := 10;
b := 20;
return (!a + !b);
}
Why is it total instead of st<h>? Won't this have a side effect of setting the references?by The_rationalist on 11/22/20, 7:52 PM
by transfire on 11/22/20, 6:03 PM
by PaulHoule on 11/22/20, 4:00 PM