More three page Scheme macros to shave off one parenthesis by implementing a bunch of complex, conditional, implicit, magic, DWIMmy conventions? Of course!
Folds are great and all but they don’t
let you easily exit early without explicitly calling a stored
continuation. So sometimes a named let
is just way easier. Except so
wordy.
Descend is sort of like a named let
except it does three magic things.
First of all, the let tag is always desc
. I almost named the macro
itself desc
but that would’ve been bad since then you couldn’t nest
them.
Second of all, if the binding is to a value of the same name e.g.
(lis lis)
you can just put the name there. You can mix these
shorthand bindings with normal bindings.
Now, if the first binding starts out as empty, the third magic thing (which I’ll get into shortly) is disabled and you can go on your merry way only using the above two magics.
(descend ((sum 0) (nums '(1 2 3 4)))
(if (null? nums) sum
(desc (+ sum (car nums)) (cdr nums))))
⇒ 10
If it starts out non-empty…
(descend ((nums '(1 2 3 4)))
(+ (car nums) (desc (cdr nums))))
⇒ 10
That’s right. It only recurs if the value is non-empty.
Here is another example of descend
used in action, to define an
“not implemented yet” operator:
(define (niy . test)
(if
(null? test)
(error "Not implemented yet!")
(descend (test)
(if (car test)
(error "Unimplemented value case!")
(desc (cdr test))))))
This errors if called with no arguments or if any of its arguments are true.
So you can stick (niy)
in a weird corner case cond clause or you can
put
(niy (null? server-response))
or whatever as a guard clause. For when you are hacking and you want to get something messy up and running quick. Sort of like a living FIXME that actually errors out.
Only the first (leftmost) descend binding is magic.
(cons (desc foo ...) bar)
or (cons bar (desc foo ...))
gets wrapped in an (if (empty? foo) (list bar) ...)
form.
(bar (desc foo ...))
gets wrapped in an (unless (empty? foo) ...)
form.
(baz (desc foo... ) bar)
or (baz bar (desc foo ...))
gets wrapped in an (if (empty? foo) bar ...)
form.
(q a b c (desc foo ...) d e f)
gets wrapped in an (if (empty foo) (q a b c d e f) ...)
form.
descend
and niy
are now part of brev-separate
.
git clone https://idiomdrottning.org/brev-separate