【问题标题】:Recommended macros to add functionality to Clojure's defrecord constructor?向 Clojure 的 defrecord 构造函数添加功能的推荐宏?
【发布时间】:2011-04-20 21:06:38
【问题描述】:

clojure 中的defrecord 允许使用自定义字段定义简单的数据容器。

例如

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

生成的最小构造函数只接受位置参数,没有其他功能,例如字段默认值、字段验证等。

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}

总是可以编写包装默认构造函数的函数来获得更复杂的构造语义——使用关键字参数、提供默认值等等。

这似乎是宏提供扩展语义的理想方案。人们为更丰富的defrecord 构造编写和/或推荐了哪些宏?

【问题讨论】:

  • 我应该指出,defrecord 在如何与 Clojure/Java 生态系统一起工作方面还有很多用处,上面的“简单数据容器”并不意味着初级,恰恰相反.
  • 需要说明的是,从clojure 1.3.0开始,你可以做到(map->Book {:author "J.R.R Tolkien", :title "The Lord of the Rings", :ISBN 9780618517657)或者#user.Book{:author "J.R.R Tolkien", :title "The Lord of the Rings", :ISBN 9780618517657}
  • 有关 Claude 指出的功能的文档,请参阅:dev.clojure.org/display/design/defrecord+improvements

标签: macros constructor clojure record


【解决方案1】:

支持完整和部分记录构造函数以及支持可评估打印和打印表单的示例:

David 是我的一位同事,我们在项目中广泛使用这个 defrecord2。我认为这样的东西真的应该成为 Clojure 核心的一部分(当然细节可能会有很大差异)。

我们发现重要的事情是:

  • 能够使用命名(可能是部分)参数构造记录:(new-foo {:a 1})
  • 能够通过复制现有记录并进行修改来构建记录:(new-foo old-foo {:a 10})
  • 字段验证 - 如果您传递声明的记录字段之外的字段,则会引发错误。当然,这实际上是合法的并且可能有用,所以有办法让它成为可选的。由于它在我们的使用中很少见,因此很可能是错误。
  • 默认值 - 这些将非常有用,但我们还没有实现它。 Chas Emerick 在这里写了关于添加对默认值的支持:http://cemerick.com/2010/08/02/defrecord-slot-defaults/
  • 打印和 pprint 支持 - 我们发现以可评估返回原始记录的形式打印和 pprint 记录非常有用。例如,这允许您运行测试、滑动实际输出、验证它并将其用作预期输出。或者从调试跟踪中滑动输出并获得真正的可评估形式。

【讨论】:

  • 完全同意一个未定义的字段可能是一个错误(但在有意时很有用)。大概知道扩展字段是故意的,它可能应该具有不同的功能,并且直接关联会引发错误。我还想知道扩展记录上的元数据是否有用。
【解决方案2】:

Here is one 定义具有默认值和不变量的记录。它创建一个可以使用关键字 args 来设置字段值的 ctor。

(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}

就像我说的......不变量:

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

但它们仅在 Trammel 的上下文中才有意义。

【讨论】:

    【解决方案3】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2011-04-17
    相关资源
    最近更新 更多