Clojure's defrecord - how to use it?

Viewed 16491

I'm attempting to create my own immutable datatype/methods with defrecord in Clojure. The goal is to have a datatype that I can create instances of, and then call its methods to return a new copy of itself with mutated variables. Say a and b are vectors. I'd like to update a value in both and return a new copy of the entire structure with those vectors updated. This obviously doesn't compile, I'm just trying to get my ideas across.

(defrecord MyType [a b]
  (constructor [N]
    ; I'd like to build an initial instance, creating a and b as vectors of length N
  ) 

  (mutate-and-return [] 
    ; I'd like to mutate (assoc the vectors) and return the new structure, a and b modified
  )
)

I'd like to call the constructor and then the mutator as many times as I'd like (there are other functions that don't mutate, but I don't want to make it more complex for the question).

Alternatively, if this is not idiomatic Clojure, how are you supposed to do something like this?

3 Answers

Clojure defrecord example:

;;define Address record

(defrecord Address [city state])

;;define Person record

(defrecord Person [firstname lastname ^Address address])

;;buid the constructor

(defn make-person ([fname lname city state]
               (->Person fname lname (->Address city state))))

;;create a person

(def person1 (make-person "John" "Doe" "LA" "CA"))

;;retrieve values

(:firstname person1)
(:city (:address person1))

Clojure allows you to create records, which are custom, maplike data types. They’re maplike in that they associate keys with values, you can look up their values the same way you can with maps, and they’re immutable like maps.


(defrecord Person [last first address])
;=> core.Person

(defrecord Ad [street city zip])
;=> core.Ad

(def p1 (Person. "Jhon" "Mick"
                 (Ad. "US187956" "NY" 3369)))
;=> #'core/p1

(update-in p1 [:address :zip] inc)
;=> #core.Person{:last "Jhon", :first "Mick", :address #playsync.core.Ad{:street "US187956", :city "NY", :zip 3370}}

(assoc p1 :last "Adam")
;=> #core.Person{:last "Adam", :first "Mick", :address #playsync.core.Ad{:street "US187956", :city "NY", :zip 3370}}
Related