简体   繁体   English

推荐的宏为Clojure的defrecord构造函数添加功能?

[英]Recommended macros to add functionality to Clojure's defrecord constructor?

defrecord in clojure allows for defining simple data containers with custom fields. clojure中的defrecord允许使用自定义字段定义简单数据容器。

eg 例如

user=> (defrecord Book [author title ISBN])
user.Book

The minimal constructor that results takes only positional arguments with no additional functionality such as defaulting of fields, field validation etc. 结果的最小构造函数只接受位置参数而没有其他功能,例如字段默认,字段验证等。

user=> (Book. "J.R.R Tolkien" "The Lord of the Rings" 9780618517657)
#:user.Book{:author "J.R.R Tolkien", :title "The Lord of the Rings", :ISBN 9780618517657}

It is always possible to write functions wrapping the default constructor to get more complex construction semantics - using keyword arguments, supplying defaults and so on. 编写包含默认构造函数的函数总是可以获得更复杂的构造语义 - 使用关键字参数,提供默认值等等。

This seems like the ideal scenario for a macro to provide expanded semantics. 这似乎是宏提供扩展语义的理想方案。 What macros have people written and/or recommend for richer defrecord construction? 人们为更丰富的defrecord构造编写和/或推荐了哪些宏?

Examples of support for full and partial record constructor functions and support for eval-able print and pprint forms: 支持完整和部分记录构造函数以及支持可评估打印和pprint表单的示例:

David is a colleague of mine and we are using this defrecord2 extensively in our project. 大卫是我的同事,我们在我们的项目中广泛使用这个defrecord2。 I think something like this should really be part of Clojure core (details might vary considerably of course). 我认为这样的事情应该是Clojure核心的一部分(细节可能会有很大不同)。

The things we've found to be important are: 我们发现重要的事情是:

  • Ability to construct a record with named (possibly partial) parameters: (new-foo {:a 1}) 能够使用命名(可能是部分)参数构造记录:(new-foo {:a 1})
  • Ability to construct a record by copying an existing record and making modifications: (new-foo old-foo {:a 10}) 能够通过复制现有记录并进行修改来构建记录:(new-foo old-foo {:a 10})
  • Field validation - if you pass a field outside the declared record fields, throw an error. 字段验证 - 如果在声明的记录字段之外传递字段,则抛出错误。 Of course, this is actually legal and potentially useful, so there are ways to make it optional. 当然,这实际上是合法的并且可能有用,因此有一些方法可以使它成为可选的。 Since it would be rare in our usage, it's far more likely to be an error. 由于它在我们的使用中很少见,因此更有可能是错误。
  • Default values - these would be very useful but we haven't implemented it. 默认值 - 这些非常有用,但我们还没有实现它。 Chas Emerick has written about adding support for default values here: http://cemerick.com/2010/08/02/defrecord-slot-defaults/ Chas Emerick撰写了关于在此处添加对默认值的支持的文章: http//cemerick.com/2010/08/02/defrecord-slot-defaults/
  • Print and pprint support - we find it very useful to have records print and pprint in a form that is eval-able back to the original record. 打印和打印支持 - 我们发现将记录打印和打印以可以回复到原始记录的形式非常有用。 For example, this allows you to run a test, swipe the actual output, verify it, and use it as the expected output. 例如,这允许您运行测试,滑动实际输出,验证它,并将其用作预期输出。 Or to swipe output from a debug trace and get a real eval-able form. 或者从调试跟踪中滑动输出并获得真正的可评估表单。

Here is one that defines a record with default values and invariants. 这是一个定义具有默认值和不变量的记录的方法。 It creates a ctor that can take keyword args to set the values of the fields. 它创建了一个ctor,可以使用关键字args来设置字段的值。

(defconstrainedrecord Foo [a 1 b 2]
  [(every? number? [a b])])

(new-Foo)
;=> #user.Foo{:a 1, :b 2}

(new-Foo :a 42)
; #user.Foo{:a 42, :b 2}

And like I said... invariants: 就像我说的那样......不变量:

(new-Foo :a "bad")
; AssertionError

But they only make sense in the context of Trammel . 但它们只在特拉梅尔的背景下才有意义。

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

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