The question here is "what's your favorite non-C-like flow control statement/construct that you've seen in a programming language" but I'm gonna start with a little preamble.
I'm very familiar with C-style flow control:
if (condition)
{ thing; }
else
{ otherThing; }
// And, thanks to C++17:
if (auto v= initializer(); condition)
{ thing(v); }
else
{ otherThing(v); }for (int i = 0; i < 5; i++)
{ thing(); }for (var e : elements)
{ thing(e); }while (condition)
{ thing(); }(plus, ya know, do/while and goto)
I've seen a few others, like Rust's loop (basically a while(true)):
loop
{
thing();
if (something)
{ break; }
}and Swift's ranges, which are nice:
for i in 0..<4
{ thing(i); }What I'm wondering is: what are your favorite bits of flow control logic (loops, jumps, conditionals, etc) that don't show up in C or C++? Are there loop forms that you think are truly elegant? Is there a switch-like construct that doesn't suck like C's switch statement does?
So I have a whole talk about this, which I could link but I feel weird about linking it because it's pre-transition and an old version, so this is kind of a Cliff Notes version of that.
Heresy is a Lisp-1 dialect I created inspired by old-school BASIC, but designed originally to teach functional programming to people who'd only ever worked in old-school imperative languages, but later mostly to teach them to myself by implementing them.
As a pure functional language, this means there is no mutability in Heresy whatsoever, and only limited side effects (just file and console, basically). But you can't write BASIC without FOR loops right? And while you can write a functional FOR loop, it's actually not a control structure that's often useful except for the side effects it generates, otherwise you'd just use a map or filter.
So we need another solution, and that solution is recursion, and escape continuations.
Here is the original macro (it has since expanded in complexity considerably, and I'm leaving some stuff off screen here):
(define-syntax-rule (for-loop var lst x body ...)
(let/ec break-k
(syntax-parameterize
((break (syntax-rules ()
[(_ ret) (break-k ret)]
[(_) (break-k)])))
(let loop ((cry-v x)
(l lst))
(syntax-parameterize
([cry (make-rename-transformer #'cry-v)])
(cond [(null? l) cry-v]
[else (let ([var (car l)])
(loop
(call/ec
(lambda (k)
(syntax-parameterize
([carry (make-rename-transformer #'k)])
body ...)
cry-v))
(cdr l)))]))))))
What we have there is a nested set of escape continuations that allow us to "break" out of the loop, as well as control when we jump to the next iteration of the loop. The loop itself is a recursive let that calls itself while carrying forward both the remaining chunk of the list and a "carry" value that we can use to build up some value to return either at the end of the loop, or explicitly through a break.
OK, that's a lot of words though, some of which I even have trouble remembering how they work, so here's a simple example of what it looks like in use:
(def fn fact (n)
(for (x in (range n to 1 step -1) with 1)
(carry (* cry x))))
This should look a lot like a for loop in BASIC but for the parens, and some weird keywords. You got your for, there's an extra range in there, but then what's the rest of it?
For starters, range is actually just a macro that adds some syntax sugar over a function that generates lists of numbers. You can actually put any list value in there, or a function call that returns a list. In this case though, we're just telling it to generate a list that starts at n and counts backward to 1.
Where the fun bit is, is with. with lets us define the starting value of cry. cry is essentially a keyword acting as a variable, and refers to an internal var we define within the loop, that initially contains the value of the with clause.
Within the body of the loop, we can call carry, and pass it a value, and it will start the next iteration of the loop with that value contained in cry.
The result is incredibly flexible, since for can iterate over anything that is a list, and with can be any value, you can do all kinds of iterative calculations in fiendish and inventive ways that Heresy's parent, Racket, needs dozens of different macros for.
And thanks to Racket's hygienic macros, we can safely nest our loops. Here we build a deck of cards with a pair of for loops (even using list ops to build the initial list for the card values). We can forgo with here because the default value of cry if not set otherwise is just the empty list.
(def cards
(for (suit in '(♠ ♣ ♥ ♦))
(carry (append (for (x in (append (range 2 to 10) '(J Q K A)))
(carry (join `(,x ,suit) cry)))
cry))))
But of course, we need not stop there. The flexibility allows us to essentially allow us to invent new kinds of control flow of a kind. Here's essentially a variadic version of the F# "forward pipe" operator, as a simple function with a for loop.
(def fn :> (initial-value . fns)
(for (f in fns with initial-value)
(carry (f cry))))
We just walk over a list of functions and apply each to cry in order. So we can do things like this:
(:> 5
inc
(partial - 5)
even?)
And we needn't stop there! With a couple little macros, next we can build the Clojure threading operator:
(def macro f> (f args ...)
(fn (x)
(f x args ...)))
(def macro -> (iv (f args ...) ...)
(:> iv
(f> f args ...)
...))
And now we can do this, just like Clojure, only underneath it all is just a for loop and some recursion!
(-> '(1 2 3 4)
(left 2)
(append '(a b)))
;=> '(1 2 a b)
But we can keep going! Remember, we can set any initial value, so ... why not a namespace. Heresy has a functional object system called Things, which are their own whole ramble for another time (they're actually lambda closures underneath!), but the short version is they work kinda like JavaScript objects in that they can kinda act like an object and kinda act like a map, so they're perfect for our purposes.
We just need to do a little set up here. First we start with an empty object:
(describe State)
And we build up some macro operations. First we need to be able to set a var:
(def macroset :=
[(:= (name ...) var value)
(fn (s) (thing extends s
(var (let ([name (s (quote name))] ...)
value))))]
[(:= var value)
(fn (s) (thing extends s (var value)))])
This one lets us just do a thing and ignore the result:
(def macroset :_
[(:_ (name ...) f args ...)
(fn (s)
(let ([name (s (quote name))] ...)
(f args ...)
s))]
[(:_ f args ...)
(fn (s)
(f args ...)
s)])
And return them ...
(def macro return (name)
(fn (s) (s (quote name))))
And finally the little rug that ties the room together:
(def fn do> fns
(apply :> (join State fns)))
So what does this do?
Do!
(do>
(:= x 5)
(:_ (x) print (format$ "Value was #_" x))
(:= (x) x (+ x 5))
(:_ (x) print (format$ "But now it's #_" x))
(:= x "Behold, a monad ... -ish.")
(return x))
;=> Value was 5
;=> But now it's 10
;=> Behold, a monad ... -ish.
Yeah we just accidentally invented Haskell's do notation in the most back-ass-ward way possible.
And underneath it all, the humble for loop.
This is the trick that made my career.

