Да, я думаю, что идиоматическое Clojure заключается в том, чтобы отделить ваши данные от ваших функций именно по той причине, что позже вы сможете написать новые функции для работы со старыми данными.
Объединение функций с данными также означает, что вы не сможете изменить свои функции позже, не изменив или заново сгенерировав все свои структуры данных, поскольку эти анонимные функции будут храниться повсеместно. Разрабатывая интерактивно в REPL, я не хотел бы выискивать все мои структуры данных, чтобы исправить их каждый раз, когда я меняю функцию. Замыкания в хэш-картах умны, но довольно хрупки, и я бы не пошел по этому пути, если бы не было действительно веской причины.
Требуется лишь небольшая дисциплина, чтобы определить ваш интерфейс (как функции), а затем не забывать придерживаться вашего интерфейса и не связываться с атомом напрямую. Неясно, какую выгоду вы получите от принудительного сокрытия вещей от себя.
Если вы хотите наследовать, мультиметоды - хороший способ сделать это.
(defmulti getc type)
(defmulti ++ type)
(defmulti -- type)
(derive ::bi-counter ::counter)
(defn make-counter
([] (make-counter 0))
([init-val]
(atom init-val :meta {:type ::counter})))
(defn make-bi-counter
([] (make-bi-counter 0))
([init-val]
(atom init-val :meta {:type ::bi-counter})))
(defmethod getc ::counter [counter]
@counter)
(defmethod ++ ::counter [counter]
(swap! counter inc))
(defmethod -- ::bi-counter[counter]
(swap! counter dec))
1010 *, например *
user> (def c (make-counter))
#'user/c
user> (getc c)
0
user> (def b (make-bi-counter))
#'user/b
user> (++ c)
1
user> (++ b)
1
user> (-- b)
0
user> (-- c)
; Evaluation aborted.
;; No method in multimethod '--' for dispatch value: :user/counter