gpt4 book ai didi

clojure - 创建与另一个相同类型的记录

转载 作者:行者123 更新时间:2023-12-01 09:15:42 25 4
gpt4 key购买 nike

我有一个案例,我想根据记录实例的类型创建一个新的记录实例,该记录实例的类型与属性映射一起作为参数出现。

(defn record-from-instance
[other attrs]
;; Code that creates the new record based on "other"
)

我现在所拥有的只是其中的一些东西:

(defn record-from-instance
[other attrs]
(let [matched (s/split (subs (str (class other)) 6) #"\.")
path (s/join "." (pop matched))
class-name (peek matched)]
((resolve (symbol (str path "/" "map->" class-name))) attrs)))

还有其他我看不到的更简单更惯用的方法吗?

谢谢!

编辑

为了提供更多详细信息,我正在构建一个以节点为记录的 AST,并且我正在使用 zipper 来访问并可能更改/删除 AST 的某些部分。我有一个 IZipableTreeNode 协议(protocol)

(defprotocol IZipableTreeNode
(branch? [node])
(children [node])
(make-node [node children]))

实现IZipableTreeNode的不同类型之间是IPersistentMap

  IPersistentMap
(branch? [node] true)
(children [node] (seq node))
(make-node [node children]
(let [hmap (into {} (filter #(= (count %) 2)) children)]
(if (record? node)
(record/from-instance node hmap)
hmap)))

当访问者说从节点中删除字段(或更改它)时,make-node 被调用,node 是记录 AST 节点,children 新的键/值对(可能不包含 node 中的某些字段)。

最佳答案

我认为 clojure.core/empty 曾经这样做过。也就是说,我认为

(defrecord Foo [x]) 
(empty (Foo. 1))

会返回

#user.Foo{:x nil}

但它现在肯定不会那样做:我不确定是改变了还是我记错了。我找不到一种 super 干净的方法来做到这一点,但我至少有比你的方法更好的方法。您正在使用的 user/map->Foo 函数是基于与类一起生成的静态方法 user.Foo/create,它在某种程度上更适合而是通过反射直接调用它。

user> ((fn [r attrs]
(.invoke (.getMethod (class r) "create"
(into-array [clojure.lang.IPersistentMap]))
nil, (into-array Object [attrs])))
(Foo. 1) {:x 5})
#user.Foo{:x 5}

但是,我现在想到你可能不需要做任何这些!您的先入之见是,实现“基于以前的事物构建新事物”的目标的方法是从头开始,但为什么要这样做呢?只要传递给您的函数的记录没有添加任何“扩展”字段(即那些不属于记录定义本身的字段),那么您可以简单地使用 clojure.core/into:

(into (Foo. 1) {:x 5}) ;=> #user.Foo{:x 5}

关于clojure - 创建与另一个相同类型的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45443819/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com