So, if you look at a recent Scheme standard such as [R7RS](https://r7rs.org/), you'll see that the body of a `lambda` expression is defined as `
* * `; zero or more internal definitions, zero or more expressions evaluated purely for their side-effects and the results discarded, and a tail expression whose evaluation result is the "return value" of the resulting procedure.
I used to find myself using the internal definitions as a kind of `let*`, writing procedures like so:
```
(lambda (foo)
(define a ...some expression involving foo...)
(define b ...some expression involving a and/or foo...)
...some final expression involving all three...)
```
But the nested defines looked *wrong* to me, and if I was to follow the specification exactly, I couldn't intersperse side-effecting expressions such as logging or assertions amongst them. And handling exceptional cases with `if` involved having to create nested blocks with `begin`.
For many cases, [`and-let*`](https://srfi.schemers.org/srfi-2/srfi-2.html) was my salvation; it works like `let*`, creating a series of definitions that are inside the lexical scope of all previous definitions, but also aborting the chain if any definition expression returns `#f`. It also lets you have expressions in the chain that are just there as guard conditions; if they return `#f` then the chain is aborted there and `#f` returned, but otherwise the result isn't bound to anything. I would sometimes embed debug logging and asserts as side-effects within expressions that returned `#t` to avoid aborting the chain, but that was ugly:
```
(and-let* ((a ...some expression...)
(_1 (begin (printf "DEBUG\n") #t))
(_2 (begin (assert (odd? a)) #t)))
...)
```
And sometimes `#f` values are meaningful to me and shouldn't abort the whole thing. So I often end up writing code like this:
```
(let* ((a ...)
(b ...))
(printf "DEBUG\n")
(assert ...)
(if ...
(let* ((c ...)
(d ...))
...)
...))
```
And the indentation slowly creeps across the page...
However, I think I have a much neater solution!
First, I'll demonstrate what it looks like, then get into how it works.
```
(block
(/let a 1)
(begin (printf "DEBUG LOGGING\n"))
(/assert (odd? a))
(/let b 3)
;; Final value expression
(+ a b))
```
`block` is my new macro, although I'd like to redefine `lambda` to wrap its body in an implicit `block` rather than invoking it directly like this. As is hopefully obvious, `(/let A B)` defines `A` to the value of `B` thereafter in the block, `begin` can be used to wrap some code to run purely for side-effects, `/assert` just checks an assertion (shorthand for `(begin (assert ...))` really), and the final expression is returned from the block.
For convenience, `/let` is defined in terms of Chicken's `match-let`, so it's destructuring - you can write:
```
(block
(/let (a b) '(1 2))
(+ a b))
```
...and get 3. I've also defined a `/flet` that's shorthand for writing a procedure, much like you can with `define`. `/flet` actually uses a `letrec` under the hood so the procedure can recursively call itself:
```
(block
(/flet (odd? x)
(cond
((zero? x) #f)
((eq? 1 x) #t)
(else (odd? (- x 2)))))
(odd? 5))
```
My `/let` just defines one thing at a time, and if you have lots of definitions, you might miss the behaviour of traditional `let`. But the good news is, you can still use it, just leave the body empty:
```
(block
(let ((a 1)
(b 2)))
(+ a b))
```
You can also use `if` to early abort, creating an effect sort of like a `cond`:
```
(define (odd? x)
(block
(if (zero? x) #f)
(if (eq? 1 x) #t)
(odd? (- x 2))))
```
This may have given you a hint as to what's going on here - all the `block` macro does is to convert its body into a kind of macro-level continuation passing style:
```
(block (A A1 A2) (B B1 B2) C) => (A A1 A2 (B B1 B2 C))
```
So when we use things like `let` and `if` in there, and `begin` for that matter, we're just wrapping the rest of the body into the final part of the `let`/`if`/`begin` form. `/let` just rewrites into a `match-let` with the final argument as its body:
```
(/let VAR VAL REST) => (matched-let ((VAR VAL)) REST)
```
Where `VAR` and `VAL` come from the `(/let ...)` expression inside the `block`, and `REST` is provided by the `block` macro itself.
This avoids out-of-control indentation for any form that nests a "body" as its final part. For instance, `handle-exceptions`:
```
(block
(handle-exceptions exn (printf "An error happened!\n" #f))
...
#t)
```
Any exceptions after the `handle-exceptions` in the block will be handled as described. For convenience, I've also defined a `/finally` that contains one or more expressions that will be executed after the rest of the `block`, whether it's an exceptional or normal exit - a bit like Go's `defer`.
Sometimes you want to use some syntax that *doesn't* have the body at the end, so I've got a macro for that, which I called `->`. It's like a sort of syntactic [`let/cc`](https://api.call-cc.org/5/doc/miscmacros/let%2Fcc), bundling the final body argument into a thunk that it binds to a chosen name:
```
(block
(-> ok (if X (ok) #f))
...)
```
If the if succeeds it will "continue" and execute the rest of the block by calling `ok`, otherwise the whole expression returns `#f`. This is equivalent to:
```
(block
(if (not X) #f))
```
Which reminds me, once can use short-circuiting `and` and `or` in a `block`, although I think it looks a little confusing!
### Conclusions
I'm not sure about the names. Ideally, I think I'd re-bind `begin` instead of `block`, and also redefine `lambda` and things that wrap it to create block structures (like `define`) to have an implicit `block` as their body.
The `/...` convention is just for things I've redefined to have a final "body argument" so they fit the `block` pattern nicely; chosen purely because `/` is an easy key to press on my keyboard and the glyph isn't too jarring, no better reason than that.
I don't like the name `->`, but have yet to think of a good, succinct, name for the operation!
### Try it yourself...
You can view [the syntax-highlighted source for Chicken 5](https://love.warhead.org.uk/~alaric/paste/block.scm.html), or download [the raw source code](http://love.warhead.org.uk/~alaric/paste/block.scm) and try it yourself. Please tell me what you think! I'd like to iterate the design a bit, tidy it up, then publish it as a Chicken egg (and maybe as an SRFI with a portable reference implementation, if there's interest?)