Lambda bodies in Scheme (by alaric)
So, if you look at a recent Scheme standard such as R7RS, you'll see that the body of a lambda
expression is defined as <definition>* <expression>* <tail expression>
; 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*
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!