Create optional fields on Clojure record? - clojure

When I instantiate a clojure record I get an error if I do not set all the fields of the record. How can I specify some of the fields to be optional?

defrecord declares a type and a constructor, but the type implements the clojure map interface. You just need to put the required fields in the declaration. For example,
(defrecord MyRecord [required1 required2])
(defn make-my-record [r1 r2 & [opt1 opt2]]
(assoc (MyRecord. r1 r2) :optional1 opt1 :optional2 opt2))
Can be used like,
user> (make-my-record 1 2)
#:user.MyRecord{:required1 1, :required2 2, :optional2 nil, :optional1 nil}
user> (make-my-record 1 2 :a :b)
#:user.MyRecord{:required1 1, :required2 2, :optional2 :b, :optional1 :a}

Related

Clojure map list of functions over hash-map, updating the hash-map each time

Say I have a board like this
(def board {:a 10 :b 12})
And a list of functions like this
(def funcs [(assoc board :a 2)
(assoc board :b 4)
(assoc board :a (inc (get board :a)))])
How would I go about applying each operation in the list to my board, having it update each time in a functional fashion.
Evaluating funcs in my repl, gives a list of return values after calling each function, but the board itself remains unchanged each time
user=> funcs
[{:a 2, :b 12} {:a 10, :b 4} {:a 11, :b 12}
Ideally I'd like the value of the board to update each time a function is ran
so after running the all commands the final state of the board should be:
{:a 3 :b 4}
I'm aware this is possible using tail recursion but I'd like to avoid doing so as I'm almost certain a combination of reduce/apply/map will do the trick
One of the defining traits of clojure is that its data structures are immutable. That means that board will never change, functions that operate on data structures return modified copies of the data structure. So what you've done in funcs is make a vector of three different boards, the original board with a fuction applied.
Usually what you want is to apply a bunch of functions to some initial value, where each function takes the returned value of the function before, then use the returned value for something. Usually passing it around in function parameters.
;; First of all, there's a function for that
(assoc board :a (inc (get board :a)))
;; The function update takes a map and a key and a function
;; It applies the function to value currently at key,
;; then sets key in the retuned "copy" of the map to be the return value of the function.
;; Equivalent to the above
(update board :a inc)
If you want an updated board with these functions applied, you need to to pass the return value through the functions, because the original board never changes, they all just return updated copies of their input.
(def updated-board
;; The innermost forms are evaluated first.
(update (assoc (assoc board :a 2) :b 4) :a inc))
This can be made more readable by using the -> or "thread first" macro. It takes an initial value and forms which are missing the first argument, then rewrites the code to "thread" the return value of each one as the first argument to the next.
(def updated-board-threaded
(-> board
(assoc :a 2)
(assoc :b 4)
(update :a inc)))
;; You can expand the macro to see for yourself
;; that the two examples are exactly equivalent.
(macroexpand-1 '(-> board
(assoc :a 2)
(assoc :b 4)
(update :a inc)))
;;=> (update (assoc (assoc board :a 2) :b 4) :a inc)
This is the way to "think in clojure", functions usually just take immutable values and return other immutable values.
But sometimes you need something mutable, and clojure delivers this in the form of atoms. An atom can be thought of as a mutable box that contains an immutable value.
It uses the functions swap! and reset! to apply controlled mutation. And the function deref to get the current value.
(def board (atom {:a 10, :b 12}))
;; I'll define a function that takes a board and returns an updated version of it.
(defn do-stuff-with-board [b]
(-> b
(assoc :a 2)
(assoc :b 4)
(update :a inc)))
;; Get the current value of board.
(deref board) ;;=> {:a 10, :b 12}
;; Swap takes an atom and a function and
;; sets the value of the atom to be the return value of the function
(swap! board do-stuff-with-board)
;; Now the mutable board atom contains a new immutable value.
(deref board) ;;=> {:a 3, :b 4}
;; derefing an atom is a very usual operation, so there's syntax sugar for it
;; Equivalent to (deref board)
#board ;;=> {:a 3, :b 4}
reset! sets the value of board to be another value, like = in "normal" languages. It's not usually idiomatic to do this as it kinda says to the reader that the new value of the atom has nothing to do with the old one, but clojure is pragmatic, and sometimes it's what you need.
(reset! board "And now for something completely different.")
;; The value is now a string.
#board ;;=> "And now for something completely different."
As an aside. The data structures are not actually deep copies of each other, there is magic behind the scenes to make it almost as efficient as updating the data structure in place, but from the perspective of the programmer they are equivalent to deep copies in other languages.
I'd like to suggest a different approach to #madstap's fine answer.
In ...
(def funcs [(assoc board :a 2)
(assoc board :b 4)
(assoc board :a (inc (get board :a)))])
... the elements such as (assoc board :b 4) are not functions: they are function calls, which, as #madstap points out, fail to modify whatever board refers to.
We can, without too much trouble, turn them into proper functions:
(def funcs [(fn [board] (assoc board :a 2))
(fn [board] (assoc board :b 4))
(fn [board] (assoc board :a (inc (get board :a))))])
The boards here are locals. Any distinct identifier would do as well:
(def funcs [(fn [b] (assoc b :a 2))
(fn [b] (assoc b :b 4))
(fn [b] (assoc b :a (inc (get b :a))))])
We can write a function to compose them:
(defn compose [fs]
(fn [x] (reduce (fn [a f] (f a)) x fs)))
This is a simplified version of the standard comp. It applies the functions first to last instead of last to first.
Now, for example, if
(def board {:a 10 :b 12})
... then
((compose funcs) board)
;{:a 3, :b 4}
Furthermore, we can modify compose to show the chain of results:
(defn compositions [fs]
(fn [x] (reductions (fn [a f] (f a)) x fs)))
((compositions funcs) board)
;({:a 10, :b 12} {:a 2, :b 12} {:a 2, :b 4} {:a 3, :b 4})
Notice that compose and compositions are completely generic - they just do stuff with functions.

Prepending metadata to a var vs. a data structure in Clojure

What, effectively, is the difference between these two metadata declarations? Why would you use one over the other?
(def a0 ^{:answer-to-everything 42} {:language "ClojureScript"})
(def ^{:answer-to-everything 42} a1 {:language "ClojureScript"})
I take it that in the first case the metadata is being prepended to the map, while in the second case the metadata is being prepended to the var. Assuming I am correct, I still don't understand why you would ever prefer one over the other.
in cases where you want to have the metadata follow the value as it's passed from function to function then use the first case. And when you don't use the second:
user> (def a0 ^{:answer-to-everything 42} {:language "ClojureScript"})
#'user/a0
user> (def ^{:answer-to-everything 42} a1 {:language "ClojureScript"})
#'user/a1
user> (print-the-metadata-from-a-function a0)
{:answer-to-everything 42}
nil
user> (print-the-metadata-from-a-function a1)
nil
nil
user> (print-the-metadata-from-a-function #'a1)
{:answer-to-everything 42, :line 74, :column 6, :file *cider-repl api*, :name a1, :ns #namespace[user]}
nil

Assoc and dissoc on Clojure records

Why is there a difference in return types of assoc and dissoc in Clojure, when their argument is a record? I mean that assoc'ing a non-existent key still returns a record, but dissoc'ing an existing key returns a map.
But, in a sense, both should produce either a map or a record, but not exhibit different behavior. What is the reason for this dissimilarity?
Record will be converted to an ordinary clojure map only if you'll dissoc one of its predefined fields. It's very reasonable behavior, because records can't have undefined fields.
Consider the following code:
(defrecord Point [x y])
(def p (Point. 1 2)) ; => Point{:x 1, :y 2}
(assoc p :x 3) ; => Point{:x 3, :y 2}
(dissoc p :x) ; => {:y 2}
(assoc p :z 3) ; => Point{:x 1, :y 2, :z 3}
(dissoc p :z) ; => Point{:x 1, :y 2}
(-> p
(assoc :z 3) ; => Point{:x 1, :y 2, :z 3}
(dissoc :z)) ; => Point{:x 1, :y 2}
As you can see, both assoc and dissoc return a record as long as it satisfies Point definition.
Record instances are guaranteed to include all the fields declared in the record definition.
When a declared field is removed from an instance, this guarantee would be violated. Hence a map is returned.
Apparently they are not guaranteed to exclude all fields not declared in the record definition, thus new fields can be added to instances.

Clojure's defrecord - how to use it?

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?
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]}
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}}

How do I create a new instance of a record?

Given that I have two objects defined (in this case records):
(defrecord rec1 [one two])
(defrecord rec2 [one two])
and I have these two records in (uninstanciated) in a list:
(def recs [rec1 rec2])
How is the best way to instanciate these two records in the list?
The following gives an exception
(map (fn [rec] (rec. 1 2)) recs)
because new and the dot constructor expects a classname-symbol. So what is the best way to go about this? So far reflection seems to be the only way:
(map #(clojure.lang.Reflector/invokeConstructor % (to-array [1 2 3])) recs)
This just seems like an overly ugly (and slow) way to perform the seemingly simple task of calling the constructor on an object. So what is the correct (or idiomatic) way?
Your question isn't clear to me, but here are some observations:
rec1 and rec2 are not different ctors of the same type, rather separate types each with 1 ctor (co-incidentally the two ctor have the same arity/ signature)
your 'uninstatiated list' doesn't make sense.
defrecord generates some helper functions for just this use...
I'm not sure exactly what you're trying to do, here are some examples that might clarify your requirements...
(def r1 (->rec1 1 2))
;=> #user.rec1{:one 1, :two 2}
(def c1 (rec1. 1 2))
;=> #user.rec1{:one 1, :two 2}
(def m1 (map->rec1 {:one 1 :two 2}))
;=> #user.rec1{:one 1, :two 2}
(def r2 (->rec2 1 2))
;=> #user.rec2{:one 1, :two 2}
(def c2 (rec2. 1 2))
;=> #user.rec2{:one 1, :two 2}
(def recs [(rec1. 1 2) (->rec1 1 2)])
(for [[n m] (partition 2 (range 4))] (->rec1 n m))
;=> (#user.rec1{:one 0, :two 1} #user.rec1{:one 2, :two 3})