Hacker News
Emulating Goto in Scheme with Continuations
Trung0246
|next
[-]
https://gist.github.com/Trung0246/8f801058212d3bbbef82690a31...
Demo (old version with outdated compile flag but still works): https://godbolt.org/z/n9ch4TM3s
It works for gcc/clang/msvc with -O0, -O1, -O2, and even -O3
taeric
|next
|previous
[-]
adrian_b
|root
|parent
|next
[-]
The Mesa restricted GOTO allowed jumping forwards, but not backwards, and it allowed jumping towards an outer block, but not towards an inner block.
These 2 restrictions eliminate all the "harmful" features of the traditional GOTO, while retaining its advantages for handling exceptional conditions or for terminating multiple levels of nested program structures.
The Common Lisp TAGBODY appears to be only partially restricted, by allowing backward jumps, so it does not prevent the kind of hard-to-understand program structures for which GOTO was criticized.
GOTOs in random directions may be used to implement state machines, but such state machines can still be implemented in a language with restricted GOTO by not using GOTO, but by using mutually recursive procedures, if tail-call optimization is guaranteed.
taeric
|root
|parent
[-]
I do think they need to be somewhat constrained to not jump to places that need new things initialized. Which, it is truly mind blowing to know folks used to just jump straight into other functions. Mid function. Because why not.
pmcgoron
|root
|parent
|next
|previous
[-]
TAGBODY doesn't actually require continuations, delimited or undelimited, just proper tail calling. A macro can rewrite each section of the TAGBODY into a procedure nested within a `let` that tail-calls its successor, and the body of the `let` tail-calls the first procedure. (GO tag) is then equivalent to just (tag). This is a great way of doing state machines. Chicken has a tagbody egg, I think.
kccqzy
|root
|parent
|next
|previous
[-]
taeric
|root
|parent
|next
[-]
Like, I have a few partial mental models for everything that they pull together. I haven't really tried to build on that, though. Should put some time to that.
richdougherty
|root
|parent
|previous
[-]
https://rd.nz/2009/03/goto-in-scala.html
It uses an experimental compiler plugin for the Scala compiler. It's typesafe at compile time. At runtime unfortunately it relies on exceptions for control flow.
Joker_vD
|root
|parent
|next
|previous
[-]
taeric
|root
|parent
[-]
The specific thing it made a lot easier was implementing algorithms the way that Knuth writes them down. Which is very much a set of steps with specific calls on what step to go to next.
I think the reason I found it fun to play with was that I found that style of laying out what needed to be done was easier to work with than the standard breakdown that making everything a function or an object seems to require. For me, it was a lot easier.
Edit: I have one of the times I used this here: https://taeric.github.io/many_sums.html I did not put any effort into cleaning up that code, though. So it can probably work as an argument in either direction. :D
soegaard
|next
|previous
[-]
https://github.com/schemedoc/bibliography/blob/master/page6....
In particular look at "Programming with Continuations", "Engines Build Process Abstractions" and "Continuations and Coroutines".
umanwizard
|previous
[-]
(define (displayln obj)
(display obj)
(newline))
(define cont #f)
(displayln
(call/cc
(lambda (k)
(set! cont k)
"cont set")))
(begin
(displayln "procedure called")
(displayln "after procedure call")
(cont "continuation called")
(displayln "after continuation call"))
will only terminate if pasted into a REPL, not if invoked from a file.This is because every top-level form in the REPL has an implicit continuation "return to the REPL and read more input".
So after "continuation called" is printed, we go back to the prompt and await more input.
However, if this code is saved in a file and you run it (e.g. "guile my-script.scm") then the continuation of the top-level `displayln` call is the top-level `begin` form, and we enter an infinite loop.