一个cond->线程宏替代,它引用谓词中的最后一个线程状态?

问题描述 投票:2回答:2

说我有这个fn

(let [{:keys [a b c d] :as params} {:a 1 :b 1 :c nil :d nil}] 
  (cond-> params
    a       (update :b inc)
    (= b 2) (assoc :c "here")
    c       (assoc :d "here")))

我得到了什么

;;=> {:a 1, :b 2, :c nil, :d nil}

我想要的是:

;;=> {:a 1, :b 2, :c "here", :d "here"}

可能的语法:

(let [params {:a 1 :b 1 :c nil :d nil}] 
  (cond$-> params
    (:a $)       (update :b inc)
    (= (:b $) 2) (assoc :c "here")
    (:c $)       (assoc :d "here")))

这个或类似的解决方案是否已在某处实施?

clojure
2个回答
3
投票

你有一个简单的实现:

(defmacro cond$->
  ([value] value)
  ([value cond body & clauses]
   (assert (even? (count clauses)))
   `(cond$-> (let [~'$ ~value]
               (if ~cond (-> ~'$ ~body) ~'$))
             ~@clauses)))

它基本上只是在第一个条件和主体上创建一个表单。如果条件匹配,则下一个cond$->调用的值将是body othervise,使用原始值。它使用递归来处理所有子句。

通常最好让用户选择用于绑定值的符号:

(defmacro cond-as->
  ([value sym] value)
  ([value sym cond body & clauses]
   (assert (even? (count clauses)))
   `(cond-as-> (let [~sym ~value]
                 (if ~cond ~body ~sym))
               ~sym
               ~@clauses)))


(let [params {:a 1 :b 1 :c nil :d nil}]
  (cond-as-> params $
             (:a $)       (update $ :b inc)
             (= (:b $) 2) (assoc $ :c "here")
             (:c $)       (assoc $ :d "here")))

1
投票

我可以看到这可能有用。你可以找到my take on it here

(let [params {:a 1 :b 1 :c nil :d nil}]
  (cond-it-> params
    (:a it)        (update it :b inc)
    (= (:b it) 2)  (assoc it :c "here")
    (:c it)        (assoc it :d "again")))

;=> {:a 1, :b 2, :c "here", :d "again"}

执行:

(defmacro cond-it->
  [expr & forms]
  (let [num-forms (count forms)]
    (when-not (even? num-forms)
      (throw (IllegalArgumentException. (str "num-forms must be even; value=" num-forms)))))
  (let [cond-action-pairs (partition 2 forms)
        cond-action-forms (for [[cond-form action-form] cond-action-pairs]
                            `(or (when ~cond-form) ~action-form)) ]
    `(it-> ~expr ~@cond-action-forms)))
© www.soinside.com 2019 - 2024. All rights reserved.