I can understand the basic case...but its totally unclear for me how to compose them.
this is kind of a fundamental issue about language development...apparently we can get used to all sorts of terrible ideas - which makes evaluating them quite difficult.
(reset val) => val
(reset E[(shift k expr)]) => (reset ((lambda (k) expr)
(lambda (v) (reset E[v]))))
; where E has no reset
E is the current-continuation of the expression, and the comment is an invariant to be held.And I think call/cc is this:
E[(call/cc k expr)] => ((lambda (k) expr) (lambda (v) E[v]))
So imagine a stack like this:
g
h
call/cc my-fun
this captures the whole stack.
And now imagine:
g
reset
h
shift my-fun
this only captures h (see how it moves the E in the reduction rules and wraps it in reset). So if I try to store k from shift and call it at a later time it won't reach g, but doing the same with call/cc it would reach g.
Some questions: - how does (both formally and from an implementation point of view) does shift find the corresponding reset? Does it relies on some sort of dynamic scoping or does the reset need to be lexically visible from the shift call? It doesn't help that in all the examples shift and resets are always called in the same expression (with shift in a lambda).
- Related to the above, how does typing work? Is the captured delimited continuation typed (i.e. does it take parameters of a specific type and returns typed values), and if so, does the typing of shift and reset need to match (racket is dynamically typed so this is not an issue there of course).
I have no formal language background, I just implement coroutines and (one shot) continuations for fun (in C++), so the key to my understanding is from an implementation point of view.
edit: from a comment elsethread it seems that I should look into effect systems.
It's dynamically scoped, which is the same as the lexical scope in the untyped lambda calculus. But yes, that is really annoying.
Example from Racket REPL:
> (require racket/control)
> (define f (lambda () (shift k (k 5))))
> (reset (f))
5
the last reset is the difference, but it seemingly makes no difference, they are interchangeable.
Of course this explanation is heavily simplified.
http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m...
It seems possible in principle: via a kind of quining, a git commit can be created whose parent hash is its own.
It involves a bit of a tough search.
[1] Constructing a cyclic git graph means finding a hash collision, and git uses SHA1 which is known to have weaknesses. With another hash algorithm it might be “practically impossible” instead of “very hard”.