Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ClojureScript映射破坏结构并填充默认值?_Clojure_Clojurescript_Destructuring - Fatal编程技术网

ClojureScript映射破坏结构并填充默认值?

ClojureScript映射破坏结构并填充默认值?,clojure,clojurescript,destructuring,Clojure,Clojurescript,Destructuring,Clojure/Script是否提供了一种方法,可以在调用中未提供键的情况下,利用参数和填充的默认值构建一个分解的映射 考虑一下这个例子(它并不完全符合代码中快速浏览的含义)。clojure是否提供了使用调用方或默认值的这四个键和值构建映射提示符。我不想再重复两次这些关键的名字来得到我想要的 (re-frame/reg-event-db :open-prompt (fn [db [_ {title :title text :text lab

Clojure/Script是否提供了一种方法,可以在调用中未提供键的情况下,利用参数和填充的默认值构建一个分解的映射

考虑一下这个例子(它并不完全符合代码中快速浏览的含义)。clojure是否提供了使用调用方或默认值的这四个键和值构建映射
提示符
。我不想再重复两次这些关键的名字来得到我想要的

(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]