ClojureScript映射破坏结构并填充默认值?
Clojure/Script是否提供了一种方法,可以在调用中未提供键的情况下,利用参数和填充的默认值构建一个分解的映射 考虑一下这个例子(它并不完全符合代码中快速浏览的含义)。clojure是否提供了使用调用方或默认值的这四个键和值构建映射ClojureScript映射破坏结构并填充默认值?,clojure,clojurescript,destructuring,Clojure,Clojurescript,Destructuring,Clojure/Script是否提供了一种方法,可以在调用中未提供键的情况下,利用参数和填充的默认值构建一个分解的映射 考虑一下这个例子(它并不完全符合代码中快速浏览的含义)。clojure是否提供了使用调用方或默认值的这四个键和值构建映射提示符。我不想再重复两次这些关键的名字来得到我想要的 (re-frame/reg-event-db :open-prompt (fn [db [_ {title :title text :text lab
提示符
。我不想再重复两次这些关键的名字来得到我想要的
(re-frame/reg-event-db
:open-prompt
(fn [db [_ {title :title
text :text
label-yes :label-yes
label-no :label-no
:or {title "Confirm"
text "Are you sure?"
label-yes "Ok"
label-no "Cancel"}
:as prompt}]]
(-> db
(update :state conj :modal-prompt)
(assoc :prompt prompt))))
在回顾了之后,我不认为Clojure提出了一种更方便的方法
但出于好奇,我想知道什么是通过解构生成的代码,因为我希望它依赖于宏。让我们来考虑这个玩具例子:
(def my-map {:text "Some text"})
(let
[{title :title
:or {title "Confirm"}
:as prompt} my-map]
(str "I got " title " from " prompt))
;; => "I got Confirm from {:text \"Some text\"}"
(macroexpand '(let
[{title :title
:or {title "Confirm"}
:as prompt} my-map]
(str "I got " title " from " prompt)))
;; => (let*
;; [map__12555
;; my-map
;; map__12555
;; (if
;; (clojure.core/seq? map__12555)
;; (clojure.lang.PersistentHashMap/create
;; (clojure.core/seq map__12555))
;; map__12555)
;; prompt
;; map__12555
;; title
;; (clojure.core/get map__12555 :title "Confirm")]
;; (str "I got " title " from " prompt))
如您所见,在宏扩展之后,允许指定默认值的:或
机制依赖于clojure.core/get
在此特定示例中,标题
受(clojure.core/get map_uu12555:title“Confirm”)
表单的影响。这是一种避免重复title
变量的方法,但值得吗
您也可以查看以获取有关它的全部详细信息,但我个人发现处理^^^非常困难。我喜欢制作一个所有默认值的映射,然后使用
到
或类似方法将用户提供的值融合到默认值的映射中。例如:
(ns tst.demo.core
(:use tupelo.core tupelo.test) )
(def stuff-default {:a 1 :b 2})
(defn apply-defaults
[arg]
(let [stuff (glue stuff-default arg)] ; or use `into`. Last one wins, so put defaults first
(with-map-vals stuff [a b]
(newline)
(spyx a)
(spyx b))
stuff))
(dotest
(is= (apply-defaults {}) ; no inputs => all default values
{:a 1, :b 2})
(is= (apply-defaults {:a 100}) ; some inputs => partial defaults
{:a 100, :b 2})
(is= (apply-defaults {:a 100, :b 200}) ; all inputs => no defaults used
{:a 100, :b 200}))
这里的glue
类似于into
,但有更多的错误检查。我们还使用tupelo.core/with-map-vals
来解构映射,其重复次数比原生Clojure解构要少(vals->map
则相反)
输出为:
-------------------------------
Clojure 1.10.1 Java 14
-------------------------------
a => 1
b => 2
a => 100
b => 2
a => 100
b => 200
Ran 2 tests containing 3 assertions.
0 failures, 0 errors.
这是可行的,虽然可能不是很实用,但对于自我教育来说很好: 让我们从构造函数开始,这将是一个特殊的绑定情况 比方说,我们希望传递长度为2或3的向量,其中2的向量将表示简单的绑定映射键值对,如
[:as abc]
或[a:a]
,大小为3的向量将是k-v-default三元组:[a:a“我的默认值”]
。其用法示例如下:
(bindings-preproc [['a 1 "asd"]
['b 2 "ddd"]
[:or {'x 10}]
[:as 'whole]])
导致
{a 1, b 2, :or {x 10, a "asd", b "ddd"}, :as whole}
此函数可以如下所示:
(defn bindings-preproc [decls]
(let [defaults (into {} (keep (fn [decl]
(when (and (not (keyword? (first decl)))
(= 3 (count decl)))
(let [[nm _ default] decl]
[nm default])))
decls))
all-kvs (apply assoc {} (mapcat (partial take 2) decls))]
(update all-kvs :or merge defaults)))
(为了说明的简单性,这个不包括错误检查)
下一步是在绑定宏中使用它。将绑定预处理
宏的想法失败了,因为在计算内部宏之前会检查绑定表单的有效性
但我们仍然有一个功能,这将有所帮助,即。例如,当您使用#inst
语法时,会使用它们。由于这些读卡器标记是在读取时处理的,所以在扩展任何宏之前,我们可以插入预处理器
(这里我将使用实际的引用更新,从repl中演示它,但在实际项目中,您将在一个特殊文件中声明这些标记)
所以,现在我们可以试着让它工作:
(defn f [#my/reader [[a :a 10]
[b :b 20]
[z :z]
[:keys [k1 k2 k3]]
[[c1 c2 & cs] :c]
[:or {z 101
k3 :wooo}]
[:as whole]]]
{:a a :b b :c1 c1 :c2 c2 :cs cs :z z :k1 k1 :k2 k2 :k3 k3 :whole whole})
user> (f {:a 1000 :c [:one]})
;;=> {:cs nil,
;; :c2 nil,
;; :z 101,
;; :c1 :one,
;; :k3 :wooo,
;; :b 20,
;; :whole {:a 1000, :c [:one]},
;; :k1 nil,
;; :k2 nil,
;; :a 1000}
user> (let [a 10
b 20
#my/reader [[x :x 1]
[y :y 2]
[z :z 100]] {:z 432}]
[a b x y z])
;;=> [10 20 1 2 432]
(defn f [#my/reader [[a :a 10]
[b :b 20]
[z :z]
[:keys [k1 k2 k3]]
[[c1 c2 & cs] :c]
[:or {z 101
k3 :wooo}]
[:as whole]]]
{:a a :b b :c1 c1 :c2 c2 :cs cs :z z :k1 k1 :k2 k2 :k3 k3 :whole whole})
user> (f {:a 1000 :c [:one]})
;;=> {:cs nil,
;; :c2 nil,
;; :z 101,
;; :c1 :one,
;; :k3 :wooo,
;; :b 20,
;; :whole {:a 1000, :c [:one]},
;; :k1 nil,
;; :k2 nil,
;; :a 1000}
user> (let [a 10
b 20
#my/reader [[x :x 1]
[y :y 2]
[z :z 100]] {:z 432}]
[a b x y z])
;;=> [10 20 1 2 432]