Comment

Comment by sdegutis

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)))
parent sdegutis 9 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton