简体   繁体   English

如何获得核心Clojure函数与defrecords一起使用

[英]How do I get core clojure functions to work with my defrecords

I have a defrecord called a bag. 我有一个录音记录袋。 It behaves like a list of item to count. 它的行为就像要计数的项目列表。 This is sometimes called a frequency or a census. 有时称为频率或人口普查。 I want to be able to do the following 我希望能够做到以下几点

(def b (bag/create [:k 1 :k2 3])  
(keys bag)
=> (:k :k1)

I tried the following: 我尝试了以下方法:

(defrecord MapBag [state]                                                                                                                                         
  Bag                                                                                                                                                             
   (put-n [self item n]                                                                                                                                          
     (let [new-n (+ n (count self item))]                                                                                                                        
          (MapBag. (assoc state item new-n))))                                                                                                                      

  ;... some stuff

  java.util.Map                                                                                                                                                   
    (getKeys [self] (keys state)) ;TODO TEST                                                                                                                      

  Object                                                                                                                                                          
   (toString [self]                                                                                                                                              
     (str ("Bag: " (:state self)))))   

When I try to require it in a repl I get: 当我尝试在repl中要求它时,我得到:

java.lang.ClassFormatError: Duplicate interface name in class file compile__stub/techne/bag/MapBag (bag.clj:12)

What is going on? 到底是怎么回事? How do I get a keys function on my bag? 如何获得行李包上的按键功能? Also am I going about this the correct way by assuming clojure's keys function eventually calls getKeys on the map that is its argument? 我是否也通过假设clojure的keys函数最终在作为其参数的映射上调用getKeys来实现这一正确方法?

Defrecord automatically makes sure that any record it defines participates in the ipersistentmap interface. Defrecord自动确保其定义的任何记录都参与了ipersistentmap界面。 So you can call keys on it without doing anything. 因此,您无需执行任何操作即可调用它的按键

So you can define a record, and instantiate and call keys like this: 因此,您可以定义一条记录,并实例化和调用键,如下所示:

user> (defrecord rec [k1 k2])
user.rec
user> (def a-rec (rec. 1 2))
#'user/a-rec
user> (keys a-rec)
(:k1 :k2)

Your error message indicates that one of your declarations is duplicating an interface that defrecord gives you for free. 您的错误消息表明您的声明之一正在复制defrecord免费提供给您的接口。 I think it might actually be both. 我认为实际上可能两者兼而有之。

Is there some reason why you cant just use a plain vanilla map for your purposes? 为什么不能出于您的目的而仅使用普通香草地图? With clojure, you often want to use plain vanilla data structures when you can. 使用clojure,您通常会希望尽可能使用普通的原始数据结构。

Edit: if for whatever reason you don't want the ipersistentmap included, look into deftype. 编辑:如果出于任何原因您不希望包含ipersistentmap,请查看deftype。

Rob's answer is of course correct; 罗伯的答案当然是正确的。 I'm posting this one in response to the OP's comment on it -- perhaps it might be helpful in implementing the required functionality with deftype . 我发布此消息是为了响应OP对它的评论-也许对使用deftype实现所需的功能可能有所帮助。

I have once written an implementation of a "default map" for Clojure, which acts just like a regular map except it returns a fixed default value when asked about a key not present inside it. 我曾经为Clojure编写了一个“默认映射”的实现,它的作用与常规映射类似,只是当被问及其中不存在的键时,它会返回一个固定的默认值。 The code is in this Gist . 代码在此要点中

I'm not sure if it will suit your use case directly, although you can use it to do things like 我不确定它是否可以直接适合您的用例,尽管您可以使用它来做类似的事情

user> (:earth (assoc (DefaultMap. 0 {}) :earth 8000000000))
8000000000
user> (:mars (assoc (DefaultMap. 0 {}) :earth 8000000000))
0

More importantly, it should give you an idea of what's involved in writing this sort of thing with deftype . 更重要的是,它应该使您了解使用deftype编写此类内容所涉及的内容。

Then again, it's based on clojure.core/emit-defrecord , so you might look at that part of Clojure's sources instead... It's doing a lot of things which you won't have to (because it's a function for preparing macro expansions -- there's lots of syntax-quoting and the like inside it which you have to strip away from it to use the code directly), but it is certainly the highest quality source of information possible. 再说一次,它是基于clojure.core/emit-defrecord ,所以您可以改用Clojure的那部分资源...它正在做很多您不需要做的事情(因为它是准备宏扩展的功能) -里面有很多语法引用等,您必须将其删除才能直接使用代码),但这无疑是可能获得的最高质量的信息来源。 Here 'sa direct link to that point in the source for the 1.2.0 release of Clojure. 这里直接链接到Clojure 1.2.0发行版中的源代码。

Update: 更新:

One more thing I realised might be important. 我意识到的另一件事可能很重要。 If you rely on a special map-like type for implementing this sort of thing, the client might merge it into a regular map and lose the "defaulting" functionality (and indeed any other special functionality) in the process. 如果您依赖于类似于地图的特殊类型来实现这种事情,则客户端可能会将其merge到常规地图中,并在此过程中失去“默认”功能(甚至其他任何特殊功能)。 As long as the "map-likeness" illusion maintained by your type is complete enough for it to be used as a regular map, passed to Clojure's standard function etc., I think there might not be a way around that. 只要您的类型所维护的“类似于地图的”幻觉足够完整,可以用作常规地图,并传递给Clojure的标准函数等,我认为可能没有办法解决。

So, at some level the client will probably have to know that there's some "magic" involved; 因此,在某种程度上,客户可能必须知道其中包含一些“魔术”; if they get correct answers to queries like (:mars {...}) (with no :mars in the {...} ), they'll have to remember not to merge this into a regular map ( merge -ing the other way around would work fine). 如果他们得到正确的答案像查询(:mars {...}):mars{...}他们将不得不记住不要merge到这个正规地图( merge -ing的其他方法也可以)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM