Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure's defrecord - how to use it?

Tags:

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?

like image 632
Eve Freeman Avatar asked Aug 14 '12 17:08

Eve Freeman


People also ask

What is Defrecord Clojure?

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.

Are there classes in Clojure?

Clojure has gen-class, reify, proxy and also deftype and defrecord to define new class-like datatypes.

What is let in Clojure?

Clojure let is used to define new variables in a local scope. These local variables give names to values. In Clojure, they cannot be re-assigned, so we call them immutable.


1 Answers

Here's how you define your record:

(defrecord MyType [a b]) 

Note that in Clojure you don't typically define "methods" within your record type itself (the exception is if you want to directly implement a Java interface or a protocol).

A basic constructor (prefixed with ->) gets generated automatically for free:

(def foo (->MyType [1 2 3] [4 5 6]))  foo => #user.MyType{:a [1 2 3], :b [4 5 6]} 

You can then write more sophisticated constructor functions that use this, e.g.

(defn mytype-with-length [n]   (let [a (vec (range n))         b (vec (range n))]      (->MyType a b)))  (mytype-with-length 3) => #user.MyType{:a [0 1 2], :b [0 1 2]} 

And "mutate-and-return" also comes for free - you can just use assoc:

(assoc foo :b [7 8 9]) => user.MyType{:a [1 2 3], :b [7 8 9]} 
like image 71
mikera Avatar answered Sep 21 '22 06:09

mikera