Подтвердить что ты не робот

Рекомендуемые макросы для добавления функциональности в конструктор defrecord Clojure?

defrecord в clojure позволяет определять простые контейнеры данных с настраиваемыми полями.

например.

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?

4b9b3361

Ответ 1

Примеры поддержки полных и частичных функций конструктора записи и поддержки для отображаемых форм печати и печати:

Дэвид - мой коллега, и мы широко используем этот defrecord2 в нашем проекте. Я думаю, что что-то вроде этого действительно должно быть частью ядра Clojure (подробности могут значительно варьироваться, конечно).

То, что мы считаем важным:

  • Возможность построения записи с именованными (возможно, частичными) параметрами: (new-foo {: a 1})
  • Возможность создания записи путем копирования существующей записи и внесения изменений: (new-foo old-foo {: a 10})
  • Проверка поля - если вы передаете поле за пределами объявленных полей записи, введите ошибку. Конечно, это действительно законно и потенциально полезно, поэтому есть способы сделать его необязательным. Так как это было бы редко в нашем использовании, это скорее всего будет ошибкой.
  • Значения по умолчанию - это было бы очень полезно, но мы его не реализовали. Chas Emerick написал о добавлении поддержки значений по умолчанию здесь: http://cemerick.com/2010/08/02/defrecord-slot-defaults/
  • Поддержка печати и печати - нам очень полезно иметь записи и печать в форме, которая может быть возвращена к исходной записи. Например, это позволяет запускать тест, прокручивать фактический вывод, проверять его и использовать в качестве ожидаемого результата. Или проведите вывод из трассировки отладки и получите реальную форму, пригодную для использования.

Ответ 2

Вот один из них, который определяет запись со значениями по умолчанию и инвариантами. Он создает 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}

И вроде я сказал... инварианты:

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

Но они имеют смысл только в контексте Trammel.