I'm currently learning Clojure and I'm a total beginner and I would appreciate some help understanding. I went through some code today and found this.
(let [timepoints (merge-with (fn [mf swt] [mf swt]) timepoint-max timepoint-sum )])
where mf, swt, timepoint-max and timepoint-sum
looks something like
{"Timepoint1": 3, "Timepoint2": 2}
So what does the code above do?
I understand that we set the variable timepoints
to be some sort of union between the two maps(?). But I'm especially confused about the fn [mf swt] [mf swt]
part.
The expression (fn [mf swt] [mf swt])
is an anonymous clojure function that constructs a vector from the two arguments passed into it, e.g
((fn [mf swt] [mf swt]) :a :b)
;; => [:a :b]
The expression (merge-with (fn [mf swt] [mf swt]) timepoint-max timepoint-sum )
is a call to the function merge-with with first argument (fn [mf swt] [mf swt])
, second argument timepoint-max
and third argument timepoint-sum
. Here is an example where we bind timepoint-max
and timepoint-sum
to some example values:
(def timepoint-max {:x 0 :y 1})
(def timepoint-sum {:y 100 :z 200})
(merge-with (fn [mf swt] [mf swt]) timepoint-max timepoint-sum)
;; => {:x 0, :y [1 100], :z 200}
Read the docs of merge-with to understand what it does:
Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter).
In the above example, what we actually compute is the same as
{:x (:x timepoint-max)
:y ((fn [mf swt] [mf swt]) (:y timepoint-max) (:y timepoint-sum))
:z (:z timepoint-sum)}
;; => {:x 0, :y [1 100], :z 200}
where the function (fn [mf swt] [mf swt])
is used to combine the two values at the only overlapping key :y
.
The full expression (let [timepoints (merge-with (fn [mf swt] [mf swt]) timepoint-max timepoint-sum )])
is a let form that binds values to symbols but it is not very useful because its *exprs
part is empty, so it always evaluates to nil
:
(let [timepoints (merge-with (fn [mf swt] [mf swt]) timepoint-max timepoint-sum )])
;; => nil
In order for it to evaluate to something else, e.g. timepoints
, it would have to be modified to something like
(let [timepoints (merge-with (fn [mf swt] [mf swt]) timepoint-max timepoint-sum) ]
timepoints)
;; => {:x 0, :y [1 100], :z 200}