Yep, overloaded language is common, and I've heard about continuations as well. First time I heard about thunks (a looong time ago) was in my 2nd year CS class that was taught in Scheme. I implemented one, and still never quite grokked what it was. The term continuation was being used as well, and I didn't know if it was the same thing or different. I hadn't heard of trampolines until fairly recently.
The next mysterious term I don't know but is probably overloaded and probably simple is monad.
Well, "continuation" is the most common name for this.
In a language like C a continuation is... the return address to the caller, and, ipliedly, the caller's frame pointer.
That is, the closure {<return address>, <frame pointer>} is a function of one argument (the value being returned). (When this finally clicked for me, a long time ago, I was astounded by the beauty and obviousness of this idea. Exclamation points abounded in my head.)
call-with-current-continuation (aka, call/cc) in Scheme is basically a reification of the caller's return closure as the "current continuation". To "reify" is a fancy term that means to "make visible an implied value" (the implied value is the return address and frame that is then made available as a first-class value).
So it's all very simple, really.
And if you structure the whole thing as a loop over calling the "current continuation" which then returns the "next current continuation", then you can move all activation frames onto the heap.
But putting each activation frame on the heap is a bit... expensive, as the work the GC has to do greatly increases, as does the amount of garbage (especially if you never call call/cc!). So the next idea is to have "delineated continuations", which... is basically like having a stack for each series of frames delineated by calls to call/cc... which is a lot like... co-routines... which people tend to implement with call/cc...
Now, monads... are a lot like such a loop over calling the current continuation. Normally, in a language like Haskell the order of evaluation of expressions is undefined for optimization reasons, and also in order to force you to have pure functions (or vice versa). Having only pure functions means that the order of evaluation can be left undefined, which increases available opportunities to parallelize, defer computation, etc... But when doing I/O, you kinda need to force some order. Well, a monad is the construct that lets you do that. In a monadic context you can think of the current continuation as not just a simple closure that returns the next current continuation, but as a closure that closes over the current state of the monad, which for the IO monad is actually the state of the world. But it's really still a plain closure at the end of the day -- one that notionally closes over more of the state of the world than a typical closure does.
Comments
Yep, overloaded language is common, and I've heard about continuations as well. First time I heard about thunks (a looong time ago) was in my 2nd year CS class that was taught in Scheme. I implemented one, and still never quite grokked what it was. The term continuation was being used as well, and I didn't know if it was the same thing or different. I hadn't heard of trampolines until fairly recently.
The next mysterious term I don't know but is probably overloaded and probably simple is monad.
Well, "continuation" is the most common name for this.
In a language like C a continuation is... the return address to the caller, and, ipliedly, the caller's frame pointer.
That is, the closure {<return address>, <frame pointer>} is a function of one argument (the value being returned). (When this finally clicked for me, a long time ago, I was astounded by the beauty and obviousness of this idea. Exclamation points abounded in my head.)
call-with-current-continuation (aka, call/cc) in Scheme is basically a reification of the caller's return closure as the "current continuation". To "reify" is a fancy term that means to "make visible an implied value" (the implied value is the return address and frame that is then made available as a first-class value).
So it's all very simple, really.
And if you structure the whole thing as a loop over calling the "current continuation" which then returns the "next current continuation", then you can move all activation frames onto the heap.
But putting each activation frame on the heap is a bit... expensive, as the work the GC has to do greatly increases, as does the amount of garbage (especially if you never call call/cc!). So the next idea is to have "delineated continuations", which... is basically like having a stack for each series of frames delineated by calls to call/cc... which is a lot like... co-routines... which people tend to implement with call/cc...
Now, monads... are a lot like such a loop over calling the current continuation. Normally, in a language like Haskell the order of evaluation of expressions is undefined for optimization reasons, and also in order to force you to have pure functions (or vice versa). Having only pure functions means that the order of evaluation can be left undefined, which increases available opportunities to parallelize, defer computation, etc... But when doing I/O, you kinda need to force some order. Well, a monad is the construct that lets you do that. In a monadic context you can think of the current continuation as not just a simple closure that returns the next current continuation, but as a closure that closes over the current state of the monad, which for the IO monad is actually the state of the world. But it's really still a plain closure at the end of the day -- one that notionally closes over more of the state of the world than a typical closure does.