|
|
|
|
|
by sdegutis
3369 days ago
|
|
For the nested if-let mess, I'd probably do something like this: (let-every [x (foo) err "foo failed"
y (bar x) err (format "bar %s failed" x)
z (goo x y) err (format "goo %s %s failed" x y)]
(qux x y z)
(handle-error err))
Where `let-every` is a macro that works like let, but stops short on the first nil/false variable, runs only the next symbol binding expression, and then runs the else-clause.There'd be nothing special about the "err" symbol on each line. It's just the next symbol binding, but on the same line as a convenience, and this means it can reference any previously valid symbol bindings. Here's a quick & dirty implementation of that macro. I don't have a Clojure interpreter installed, so I don't know if it works. (defmacro let-every [bindings if-body else-body]
(let [pairs (partition 2 bindings)
quad-pairs (partition 2 pairs)]
(loop [quad-pairs quad-pairs]
(if quad-pairs
(let [[quad-pair] quad-pairs
[try-pair err-pair] quad-pair
[try-sym try-expr] try-pair
[err-sym err-expr] err-pair]
`(if-let [~try-sym ~try-expr]
(recur (next quad-pairs))
`(let [~err-sym ~err-expr]
~else-body)))
if-body))))
Given the above example, it should expand to this: (if-let [x (foo)]
(if-let [y (bar x)]
(if-let [z (goo x y)]
(qux x y z)
(let [err (format "goo %s %s failed" x y)]
(handle-error err)))
(let [err (format "bar %s failed" x)]
(handle-error err)))
(let [err "foo failed"]
(handle-error err)))
|
|
If we are going to just propagate `nil`, then if we have an `iflet` that tests the last variable, we can do:
it's just a bit verbose. That can be condensed with a simpler macro that doesn't have the err stuff.