2024 年 Clojure 调查 中分享您的想法!

欢迎!有关更多信息,请参阅 关于 页面。

0
集合
目前,Clojure 的解构实现会将任何满足 clojure.core/seq? 的值创建为 hash-map。我争辩说这有一个不希望产生的副作用,即使得在同时是一个自定义的关联类型和一个序列的关联类型上进行解构变得不可能。这在尝试解构标签值类的实例时出现,这些实例在模式匹配方面行为就像 [k v] 序列,但由于 v 已知是映射,因此在映射部分上也具有关联性,以避免更新保留标签的语法开销。


;; 此类型的一个草图
(deftype ATaggedVal [t v]
  clojure.lang.Indexed
  (nth [self i]    (nth self i nil))
  (nth [self i o] (case i (0) t (1) v o))

  clojure.lang.Sequential
  clojure.lang.ISeq
  (next  [this]     (seq this))
  (first [this]     t)
  (more  [this]     (.more (seq this)))
  (count [this]     2)
  (equiv [this obj] (= (seq this) obj))
  (seq   [self]     (cons t (cons v nil)))

  clojure.lang.Associative
  (entryAt [self key] (.entryAt v key))
  (assoc [_ sk sv]    (ATaggedVal. t (.assoc v sk sv)))

  clojure.lang.ILookup
  (valAt [self k]   (.valAt v k))
  (valAt [self k o] (.valAt v k o))

  clojure.lang.IPersistentMap
  (assocEx [_ sk sv] (ATaggedVal. t (.assocEx v sk sv)))
  (without [_ sk]    (ATaggedVal. t (.without v sk))))


因此使用这样的事物,


(let [{:keys [x]} (ATaggedVal. :foo {:x 3 :y 4})] x)
;; 期望 3
=> nil


由于对于任何满足 clojure.core/get 将表现行为的类型 T,T 应该满足 clojure.core/map?, должно было быть в correto simplesmente mudar o comportamento da destruturação para construir um hash-map apenas se map? não for satisfeito.

附带补丁实现此更改。

4 个回答

0

评论者:alexmiller

也许还应该关注CLJ-1778,它可能会导致这项功能不再适用。

能否在描述中添加一个示例说明哪些情况不起作用?

0
_评论者:ragge_

CLJ-1778的当前补丁没有解决这个问题。

在我看来,这个想法似乎很合理,如果我们正在解构一个已经是地图的值(由{{map?}}确定),我们就不需要通过调用{{seq}}和{{HashMap/create}}来创建一个新的地图,除非有充分的理由应该使用具体的地图实现(我看不出)。
如果{{seq}}和{{HashMap/create}}确实应该被调用,除非有充分的理由应该使用具体的地图实现(我看不出)。
除非有充分的理由应该使用具体的地图实现(我看不出)。
除非有充分的理由应该使用具体的地图实现(我看不出)。
除非有充分的理由应该使用具体的地图实现(我看不出)。

但是我认为当前的补丁并不好,因为它的行为对地图解构做了不必要的破坏性更改。
之前,解构一个不可序列化的值会返回nil,但是随着这个补丁,{{seq}}总是对值进行调用,对于不可序列化的类型,这会抛出异常。应该很容易将补丁修改回去以保持原始的行为。
之前,解构一个不可序列化的值会返回nil,但是随着这个补丁,{{seq}}总是对值进行调用,对于不可序列化的类型,这会抛出异常。应该很容易将补丁修改回去以保持原始的行为。
应该很容易将补丁修改回去以保持原始的行为。
应该很容易将补丁修改回去以保持原始的行为。
应该很容易将补丁修改回去以保持原始的行为。

1.8.0大师

user=> (let [{:keys [x]} (java.util.Date.)] x)
nil


通过 0001-Enable-destructuring-of-seq-map-types.patch


user=> (let [{:keys [x]} (java.util.Date.)] x)
IllegalArgumentException 无法从:java.util.Date 创建ISeq  clojure.lang.RT.seqFrom (RT.java:528)

0
_评论者:arrdem_

我认为被破坏的行为最多是随实施而来的未定义行为,而未能抛出异常的转换至少比原实施方式中的静默nil行为更清晰。

我 personally prefer to extend the destructuring checks logically to {{(cond map? x seq? (hash-map (seq x)) :else (throw "Failed to destructure non-map type")}} but I think that change is sufficiently large that it would meaningfully decrease the chances of this patch being accepted.
0
参考:https://clojure.atlassian.net/browse/CLJ-1803(由 arrdem 报告)
...