(into) 是否进行任何更高级别的推理以保持输出类型的惯用性?

Does (into) do any higher-level inference to stay idiomatic on output type?

假设我有一个键值对,我不可知论地定义为键值映射:

(def foo {:bar "baz" :bat "squanch"})

稍后我想到要对它做一些集合操作,所以我需要将它转换成一个关系,Clojure 速查表说这是一种集合,所以我继续抓住(into) 并前往:

(set/project (into #{} foo) [:bar])
#{{}}

嗯?

(into #{} foo)
#{[:bar "baz"] [:bat "squanch"]}

这根本不是 (project) 所期望的。根据 the docs:

;; `project` strips out unwanted key/value pairs from a set of maps. 
;; Suppose you have these descriptions of cows:

user=> (def cows #{  {:name "betsy" :id 33} {:name "panda" :id 34} })
#'user/cows

;; You care only about the names. So you can get them like this:

user=> (project cows [:name])
#{{:name "panda"} {:name "betsy"}}

这么近。

当我转换成其中一种类型时,我是否应该期望 (into) 知道我的意思,还是有其他方法?如果它会像这样,我还不如通过几个 map/flatten 调用来完成我自己的事情,但这正是我试图通过用更优雅的集合语言来表达事物来避免的。

为清楚起见,这里有一个我认为最好用(set/project)完成的事情的例子,这似乎无法满足上述期望:

(defn exclude-keys "Filters out all but argument-provided keys from a key-value
  map."
  [input-map excluded-keys]
  (-> input-map (select-keys (set/difference (into #{} (keys input-map))
                                              excluded-keys))))

我想我只是对在 Clojure 中需要那么多额外的语法感到惊讶。

into 只是 conj 将序列的元素放入给定的集合中,例如

(into #{} [:a :b :b :c :a])
=> #{:c :b :a}

由于映射是对的序列,因此您最终会在输入映射中得到一组对。

如果您只想从地图中删除一组键,您可以使用 dissoc:

(defn exclude-keys "Filters out all but argument-provided keys from a key-value
  map."
  [input-map excluded-keys]
  (apply dissoc input-map excluded-keys))