2024年Clojure调查问卷!分享您的想法。

欢迎!请参阅关于页面以了解有关该功能的更多信息。

0
Collections
目前,Clojure的解构实现将从满足clojure.core/seq?的任何值创建一个HashMap。我认为这产生了不希望产生的副作用,使得在使用自定义的也是Seq的关联类型时无法使用解构。在尝试解构标记值类的实例时出现了这种情况,该实例在模式匹配时以[k v]的方式作为seq,但由于v已知是map,因此还关联在map部分,以避免更新保留标签时的语法开销。


;; 此类型的一个草图
(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,它应满足clojure.core/map?,因此只需简单地修改解构的行为,只在全球表中不满足map?时才构建HashMap。

附带的补丁实现了这一更改。

4 个答案

0

评论者:alexmiller

也许还值得关注CLJ-1778,它可能会使这个不再适用。

能否在描述中添加一个不工作的示例?

0
_评论者:ragge_

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

在我看来,这个想法听起来不错,如果我们映射解构一个本身就是映射的值(由{{map?}}确定),我们不需要通过调用{{seq}}和{{HashMap/create}}来创建一个新映射,除非有非常好的理由它应该正好是这个映射实现(我没看到)。
第9行
除非真的有一个非常好的理由它应该正好是这个映射实现(我看不到一个)。
第11行
第12行

但我认为当前的补丁并不好,因为它对映射解构的行为做了(不必要的)破坏性更改。
之前,解构一个不可映射的值返回nil,但通过与补丁,{{seq}}总是会调用值,对于非映射类型这将产生一个异常。应该很容易将补丁更改以保持原始行为。
第16行
应该很容易将补丁更改以保持原始行为。
第18行
第19行

nil

第21行
第23行


第23行


第21行
与 0001-Enable-destructuring-of-seq-map-types.patch

0
IllegalArgumentException 无法从:java.util.Date创建ISeq  clojure.lang.RT.seqFrom (RT.java:528)
_评论者:arrdem_

我争辩说,被破坏的行为至多是不确定的实现后果,而无法进行类型转换异常至少比原有实现的静默nil行为清楚。

我个人更愿意将逻辑上扩展到{{(cond map? x seq? (hash-map (seq x)) :else (throw "Failed to destructure non-map type"))}},但我想,这个变化足够大,可能会大幅降低此补丁被接受的机会。
0
...