diff --git a/site-src/ccgoto.mdx b/site-src/ccgoto.mdx
index 9416de4..ec4d0ba 100644
--- a/site-src/ccgoto.mdx
+++ b/site-src/ccgoto.mdx
@@ -1,21 +1,291 @@
---
title: Emulating GOTO in Scheme with continuations
-description: GOTO sucks and is evil and I hate it, but what if there were parentheses? `call/cc` is kinda like goto, so let's make goto.
+description: GOTO sucks and is evil and I hate it, but what if there were parentheses? `call/cc` is kinda like goto, so let’s use it to make goto.
tags: post,short
date: 2026-02-18 14:28:46 -5
---
+
+In his 1968 letter, [A case against the GO TO statement](https://www.cs.utexas.edu/~EWD/transcriptions/EWD02xx/EWD215.html)
+(known only by that name), Dijkstra said “[t]he go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one’s program.”
+Unfortunately, scheme programmers aren’t given that invitation.
+That’s no fair!
+Fortunately, scheme has a procedure, `call/cc`, that we can use to emulate the control flow that `GOTO` provides.
+We can use syntactic abstraction to invite our scheme programmers to make a mess of their programs in a limited context.
+
+{/*TODO actually complete intro*/}
+{/*todo revision*/}
+
+## How `GOTO` works
+Odds are, you know how `GOTO` works, but let’s briefly review.
+Perhaps you’ve seen a BASIC program that looks something like this:
```basic
10 PRINT "Hello, world!"
20 GOTO 10
```
-Here is some `inline code`.
+This, as you may have guessed, outputs:
-```js
-console.log("Surely, javascript is supported");
+```text
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+...
+```
+…forever.
+
+Normally, control proceeds from the lowest line number to the highest line number, but the `GOTO` statement “jumps” to the given line, no matter where it is.
+(Forgive my imprecision, this is not a BASIC tutorial.)
+
+You’re more likely to see `goto` in `C`:
+
+```c
+void do_something() {
+ char *important_stuff = (char*)malloc(/* ... */);
+ FILE *important_file = fopen(/* ... */);
+
+ // do stuff...
+ if (errno != 0) goto cleanup;
+
+ // do more stuff...
+ if (errno != 0) goto cleanup;
+
+ printf("Success!\n");
+
+ // control falls through even if everything goes well
+
+cleanup:
+ free(important_stuff);
+ fclose(important_file);
+}
```
-```ruby
-3.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.
+Using `goto` here let’s us avoid repeating the `cleanup` logic.
+Not my thing, but this is what `goto` fans like.
+In `C`, `goto` uses `labels:` instead of line numbers, and it can’t leave the function, but otherwise it is substantially similar to BASIC’s `GOTO`.
+
+Hopefully you understand `goto` now. It lets you jump around.
+The second thing you need to understand before we can implement `goto` with `call/cc` is how `call/cc` works.
+
+## How `call/cc` works
+`call/cc` is short for `call-with-current-continuation`.
+
+Oh, you wanted more explanation? Ugh, fiiiine.
+A certain smart guy once said that “[i]f you can't explain it simply, you don't understand it well enough.”
+So, let's see if I understand `call/cc` well enough.
+
+`call/cc` takes one argument, a procedure, and returns the result of applying that procedure with the current continuation as an argument.
+
+What is “the current continuation?”
+Let’s start with an example.
+```scheme
+(define cont #f)
+(begin
+ (+ 1 (call/cc
+ (lambda (k)
+ (set! cont k)
+ 0)))
+ (display "The number is: ")
+ (write (cont 41))
+ (newline))
+
```
+If we run this program, `cont` will be a procedure that adds `1` to its argument.
+Seems useless, but let's run it anyway. It outputs:
+```
+The number is: The number is: The number is: ...
+```
+…forever‽
+
+Continuations are a lot like procedures, but they don’t necessarily come back to where you called them.
+
+`cont` is actually something like
+```scheme
+(define cont
+ (lambda (x)
+ (+ 1 x)
+ (display "The number is: ")
+ (write (cont 41))
+ (newline)))
+```
+In this form, the unconditional recursion is obvious.
+
+The `k` that `call/cc` calls its argument with represents, roughly, the rest of the computation.
+The “current continuation” is what will be executed next at the point that `call/cc` is called.
+
+Incidentally, this helps me understand scheme’s multiple return values; `(values v1 v2 ...)` is just `(call/cc (lambda (k) (k v1 v2 ...)))`.
+
+I recommend reading about continuations in Dybvig’s [The Scheme Programming Language](https://www.scheme.com/tspl4/further.html#g63)
+if you’re (justly) dissatisfied with my explanation or just want to learn more about how they work and their applications.
+
+We talked about how `call/cc` works, so let’s finally use it to implement `goto` in scheme!
+
+## `goto` in scheme
+Here you go:
+```scheme
+(define-syntax with-goto
+ (syntax-rules ()
+ [(_ goto rest ...)
+ (let ()
+ (define goto #f)
+ (%labels rest ...)
+ (call/cc
+ (lambda (k)
+ (set! goto
+ (lambda (label) (k (label))))
+ rest ...)))]))
+
+(define-syntax %labels
+ (syntax-rules ()
+ [(_) (begin)]
+ [(_ (_ ...) rest ...) (%labels rest ...)]
+ [(_ label rest ...)
+ (begin
+ (define (label) rest ...)
+ (%labels rest ...))]))
+```
+Let’s run that with our favorite [R⁶RS](https://www.r6rs.org/) implementation (mine is [Chez Scheme](https://cisco.github.io/ChezScheme/)):
+```scheme
+(with-goto goto
+ loop (display "Hello, world!\n")
+ (goto loop))
+```
+
+```text
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+...
+```
+
+Here’s an example that doesn't loop forever:
+```scheme
+(let ([x 1])
+ (with-goto go
+ (go loop)
+ double
+ (set! x (* 2 x))
+ loop
+ (display x) (newline)
+ (when (< x 1000)
+ (go double))
+ (display "done\n")))
+```
+It outputs:
+```scheme
+1
+2
+4
+8
+16
+32
+64
+128
+256
+512
+1024
+done
+```
+
+I’ll explain this macro one part at a time.
+
+First, `(define-syntax goto (syntax-rules () [...]))` defines `goto` as a syntax transformer (more precise name for a macro) using the `syntax-rules` pattern-matching language.
+The `()` after `syntax-rules` is the empty list of literals; we don't have any special words here, so it doesn't apply.
+You can read more about how `syntax-rules` works in [TSPL](https://scheme.com/tspl4/syntax.html#./syntax:s14), but we'll only be using the most basic features here.
+The important thing is to know that matched names are replaced in the output and that `x ...` matches/splices zero or more expressions.
+Also, `syntax-rules` is hygienic, so don’t stress about name collisions.
+
+Then, we match `(_ goto rest ...)`.
+Anything else is a syntax error.
+The `_` is for `with-goto` (we do not want to repeat ourselves).
+
+We output a big `let` expression.
+Notice how the second example uses `go` instead of `goto`?
+That's because the first element in `with-goto` is the name of the `goto` procedure.
+We `define` it as false because we will set it later.
+
+Next, we pass the body (`rest ...`) to `%labels`, which deserves its own heading.
+
+## Extracting labels
+`%labels` is a syntax transformer with three cases:
+1. `(_)` Nothing is passed: `(begin)` (do nothing)
+2. `(_ (_ ...) rest ...)` A list is passed: Ignore it and process `rest ...`. We treat expressions of the form `(x ...)` as statements, not labels.
+3. `(_ label rest ...)` Finally, a label!
+
+When we encounter a label, we define a thunk (procedure that takes no arguments) with the rest of the arguments as its body, like so:
+```scheme
+(define (label) rest ...)
+```
+
+Putting it all together,
+```scheme
+(%labels
+ a
+ (display 1)
+ b
+ (display 2)
+ c
+ (display 3))
+```
+(morally) expands to
+```scheme
+(begin
+ (define (a)
+ (display 1)
+ b
+ (display 2)
+ c
+ (display 3))
+
+ (define (b)
+ (display 2)
+ c
+ (display 3))
+
+ (define (c) (display 3)))
+```
+(The leftover labels have no effect)
+
+This helper on its own is a really crappy way to define functions with shared tails, so let’s bring it all together.
+
+## Going to
+We have our labels as functions, but what for?
+If we call these procedures, they will return control to us, so they aren’t like `C` labels at all.
+Well, remember how I said that continuations don’t necessarily come back to where you called them?”
+We’re going to exploit that property to implement `goto`.
+We wrap the body of `with-goto` in `(call/cc (lambda (k) ...))`.
+
+Now, inside the body, if we call `k`, instead of continuing execution, we'll immediately stop.
+By calling a label before `k`, we effectively jump from whatever we were doing to whatever follows the label.
+This is exactly the behavior we were looking for!
+
+`(set! goto (lambda (label) (k (label))))` makes `goto` do exactly this (function arguments have to be evaluated before the procedure call takes place).
+We use `(define goto #f)` combined with a `set!` because the labels we defined earlier need to be able to see the `goto` function.
+
+This is what our first `with-goto` looks like when we expand it:
+```scheme
+(let ()
+ (define goto #f)
+ (define (loop) (display "Hello, world!\n") (goto loop))
+ (call/cc
+ (lambda (k)
+ (set! goto (lambda (label) (k (label))))
+ loop
+ (display "Hello, world!\n")
+ (goto loop))))
+```
+(It is in fact expanded slightly differently and more efficiently, it does not use unbounded stack space afaik, which makes sense because we aren’t actually increasing the depth of the callstack when we `goto`.)
+
+## Conclusion
+This is useless.
+There are a lot of cool things that you can implement with `call/cc`, but this is dumb!
+There is a *lot* of nonsense that you can do with this implementation (try messing with nested `with-goto` or storing `goto` elsewhere).
+Still, I hope you learned a bit about `call/cc` and what building abstractions with it can look like.
+
+Unfortunately, [`call/cc` sucks](https://okmij.org/ftp/continuations/against-callcc.html)!
+This has been known for decades!
+[Delimited continuations](https://en.wikipedia.org/wiki/Delimited_continuation) are way better!
+Use the [`⁻Ƒ⁻` operator](https://web.archive.org/web/20250112082613/https://legacy.cs.indiana.edu/~dyb/pubs/monadicDC.pdf)!
+Thanks for the soapbox.