Fork me on GitHub
#clojure-uk
<
2021-08-20
>
djm05:08:34

๐Ÿ‘‹

3
dharrigan06:08:20

Good Mornin!

dharrigan06:08:10

Does anyone have a nice way of handling destructuring of (for example) a map, using a when-let form so that if the destructured values are nil, not to eval the body of the form?

Ed12:08:21

how about

(defmacro when-let-destruct [bindings & body]
  (let [local? (->> bindings (partition 2) (map first)
                    (tree-seq (fn [x] (and (not (string? x)) (seqable? x))) seq)
                    set)]
    `(let ~bindings
       (when (and ~@(->> bindings destructure (partition 2) (map first) (filter local?) distinct))
         ~@body))))

(macroexpand-1 '(when-let-destruct [{:keys [a b]} {:a 1 :c 2}] (+ a b))) ;; => (clojure.core/let [{:keys [a b]} {:a 1, :c 2}] (clojure.core/when (clojure.core/and a b) (+ a b)))
(when-let-destruct [{:keys [a b]} {:a 1 :c 2}] (+ a b)) ;; => nil
(when-let-destruct [{:keys [a b]} {:a 1 :b 2}] (+ a b)) ;; => 3
???

dharrigan06:08:23

(when-let [{:keys [a]} {:a {:b 1} :c 2}]
  (str "The value is '" a "'")) ;; "The value is '{:b 1}'"

(when-let [{:keys [d]} {:a {:b 1} :c 2}]
  (str "The value is '" d "'")) ;; "The value is ''"

dharrigan06:08:08

In the second example, I don't want the body to eval. I understand the when-let form does the let part first, as can be seen from expanding the macro out...

dharrigan06:08:33

(clojure.core/let [temp__4165__auto__ {:a {:b 1}, :c 2}] 
  (clojure.core/when temp__4165__auto__ 
    (clojure.core/let [{:keys [d]} temp__4165__auto__] 
      (str "The value is '" d "'"))))

dharrigan06:08:07

Any suggestions?

djm07:08:30

I donโ€™t know about a nice way, but perhaps you could do something with some->, or else wrap a let with when-let

Jakob Durstberger07:08:37

Happy Friday ๐Ÿ‘‹

jiriknesl14:08:20

Good afternoon ๐Ÿ™‚