Nesting vs Threading vs let - clojure

Clojure newcomer here, which of the following forms do you consider most "clojuresque":
Heavily nested
(my-fn3 (my-fn2 (my-fn1 foo bar) baz) qux)
Using let
(let [result foo
result (my-fn1 result bar)
result (my-fn2 result baz)
result (my-fn3 result qux)])
Using thread-first
(-> foo
(my-fn1 bar)
(my-fn2 baz)
(my-fn3 qux))

I use all 3 techniques, depending on the situation. The goal is to pick the technique that makes the code the most clear (not the fewest characters!).
Technique #2 is especially handy when debugging, as you can easily print out intermediate values. However, I normally give each stage a distinct name to clarify the situation:
(let [x-1 foo
x-2 (my-fn1 x-1 bar)
x-3 (my-fn2 x-2 baz)
x-4 (my-fn3 x-3 qux)]
(println :x-1 x-1)
(println :x-2 x-2)
(println :x-3 x-3)
(println :x-4 x-4)
x-4) ; don't forget to return the final result!
Update
On the subject of debugging, this is how I would do it. First, the 3 versions raw:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn fa [x y] (+ x y))
(defn fb [x y] (* x y))
(defn fc [x y] {:x x :y y})
(def tgt 2)
(defn stack-nest
[foo]
(fc
(fb
(fa foo 3)
3)
99))
(defn stack-thread
[foo]
(-> foo
(fa 3)
(fb 3)
(fc 99)))
(defn stack-let
[foo]
(let [a foo
b (fa a 3)
c (fb b 3)
d (fc c 99)]
d)) ; don't forget to return the final result!
You don't need to invent your own dbg function, as there are already some good options in the Tupelo library. Here, we print the results using the spyx (spy explicit) macro:
(dotest
(spyx (stack-nest tgt))
(spyx (stack-thread tgt))
(spyx (stack-let tgt)))
(stack-nest tgt) => {:x 15, :y 99}
(stack-thread tgt) => {:x 15, :y 99}
(stack-let tgt) => {:x 15, :y 99}
We then add debugging info using spy and a label:
(defn stack-nest
[foo]
(spy :fc (fc
(spy :fb (fb
(spy :fa (fa foo 3))
3))
99)))
:fa => 5
:fb => 15
:fc => {:x 15, :y 99}
(stack-nest tgt) => {:x 15, :y 99}
It works, but it's pretty ugly. How about the threading form? Here we can insert spy and it's a bit better:
(defn stack-thread
[foo]
(-> foo
(spy :foo)
(fa 3)
(spy :fa)
(fb 3)
(spy :fb)
(fc 99)
(spy :fc)
))
:foo => 2
:fa => 5
:fb => 15
:fc => {:x 15, :y 99}
(stack-thread tgt) => {:x 15, :y 99}
We get what we want, but it's got some duplication. Also, we need to put each (spy ...) expression on a separate line so the threading macro -> sends the value to both the computation like (fa 3) and the printing step like (spy :fa).
We can simplify it a bit with the it-> macro like so:
(defn stack-thread-it
[foo]
(it-> foo
(fa it 3)
(fb it 3)
(fc 99 it)))
We use the symbol it as a placeholder. Note that we can place the threaded value in any argument position, as shown by the reversed args to fc. For our debugging, use spyx so the expressions are self-labeled, and we get:
(defn stack-thread-it
[foo]
(it-> (spyx foo)
(spyx (fa it 3))
(spyx (fb it 3))
(spyx (fc 99 it))))
foo => 2
(fa it 3) => 5
(fb it 3) => 15
(fc 99 it) => {:x 99, :y 15}
(stack-thread-it tgt) => {:x 99, :y 15}
When intermediate variables are in a let expression, I debug like so:
(defn stack-let
[foo]
(let [a foo
>> (spyx a)
b (fa a 3)
>> (spyx b)
c (fb b 3)
>> (spyx c) ]
(spyx (fc c 99))))
a => 2
b => 5
c => 15
(fc c 99) => {:x 15, :y 99}
(stack-let tgt) => {:x 15, :y 99}
Note that the last function fc is invoked directly as the return value (outside of the let), but we can still print its value using spyx.
Note that I like to use the symbol >> (unused anywhere in Clojure) instead of the underscore _ as the dummy recipient of the expression value, as the underscore is sometimes difficult to see. The >> symbol not only stands out in the code, but also looks a bit like a command-line prompt, reminding one of the imperative, side-effecting nature of the print action.

I would say that often a combination of approach 2 and 3 is what most people strive towards when writing Clojure, simply because it provides the most readability.
Typically you'll want to use lets where the values you're binding will be used in multiple places, e.g. you'll need a particular value that will be used to create another binding and that value will also be used inside the body of the let.
Now, approach 3 isn't always achievable, in some cases you'll run into a situation where two function calls don't share the same ordinal position for the value you're threading, which will either require a re-think/structuring the code slightly differently, or you can reach for the as-> operator, which I personally find rather hideous.
I often find with Clojure that the readability of the code reflects its idiomaticy, if something does look right, there's almost always a better way to write it.

Related

How to get an element in a matrix in clojure

I have a vector of vectors [[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]] containing x,y positions of detected plates.
How do I retrieve the x position of plate p3?
It seems to be a simple task but I'm more familiar with python, so I'm not sure how to do this in clojure.
i would go with something like this:
(def data [[:plate "p1" 0 1] [:plate "p2" 0 2] [:plate "p3" 1 1]])
(some (fn [[_ v x y]] (when (= v "p3") [x y])) data)
;;=> [1 1]
(some (fn [[_ v x y]] (when (= v "p123") [x y])) data)
;;=> nil
(def p '[[plate,"p1",0,1],[plate,"p2",0,2],[plate,"p3",1,1]])
;; be aware, 'p1' you can use in Python, but because in Clojure `'` at beginning
;; of a symbol is parsed as `quote`, you can't use `''` instead of `""` in contrast to Python.
;; create a nested map out of the vec of vecs
(defn vecs-to-map [vecs]
(reduce (fn [m [_ id x y]] (assoc m id {:x x :y y}))
{}
vecs))
(def m (vecs-to-map p))
;;=> {"p1" {:x 0, :y 1}, "p2" {:x 0, :y 2}, "p3" {:x 1, :y 1}}
;; you can access such a nested list via `get-in` and giving the nested map
;; and the keys it should apply on it.
(get-in m ["p3" :x])
;;=> 1
Since the irregularity that one key is a string and the other a keyword is
not so nice, I would make out of them all keywords:
(defn vecs-to-map [vecs]
(reduce (fn [m [_ id x y]] (assoc m (keyword id) {:x x :y y}))
{}
vecs))
(def m (vecs-to-map p))
;; access it by:
(get-in m [:p3 :x])
;;=> 1
Additional Thoughts
We ignored the first element of the vec plate.
Let's say there exist also another vectors like
(def b '[[box "b1" 0 1] [box "b2" 0 2] [box "b3" 1 1]])
And if we want a nested map which contains :plate and :box in the
outer level as keys, we have to change the vecs-to-map function.
(defn vecs-to-map [vecs]
(reduce (fn [m [k id x y]] (assoc m (keyword k)
(assoc (get m (keyword k) {})
(keyword id) {:x x :y y})))
{}
vecs))
Then we can generate the map containing everything by:
(def m (vecs-to-map (concat p b)))
;; or alternatively in two steps:
;; (def m (vecs-to-map p))
;; (def m (merge m (vecs-to-map b)))
m
;; => {:plate {:p1 {:x 0, :y 1}, :p2 {:x 0, :y 2}, :p3 {:x 1, :y 1}}, :box {:b1 {:x 0, :y 1}, :b2 {:x 0, :y 2}, :b3 {:x 1, :y 1}}}
And we access the content by:
;; access through:
(get-in m [:plate :p3 :x])
;; => 1
(get-in m [:box :b2 :y])
;; => 2
You don't really provide much context on what you're trying to do but it feels like you want to filter the vector of tuples to those that have the symbol p3' in the second position and then return just the third and fourth elements of such a match?
If so, the following would work:
dev=> (def plate :plate)
#'dev/plate
dev=> (def data [[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]])
#'dev/data
dev=> (let [[[_ _ x y]] (filter (comp #{'p3'} second) data)]
#_=> [x y])
[1 1]
This doesn't feel very idiomatic, so perhaps you could explain more of the context?
Note: 'p3' is a symbol whose name is p3' so I wonder if you mean "p3" for a string?
The vector of vector format doesn't seem very conducive to the sort of access you want to perform - perhaps changing it to a hash map, whose keys are the plate IDs (if that's what p1, p2, and p3 are?) would be better to work with?
Edit: in response to #leetwinkski's note about the result when there is no match, here's an alternative:
You could use when-first:
dev=> (when-first [[_ _ x y] (filter (comp #{'p123'} second) data)]
#_=> [x y])
nil
dev=> (when-first [[_ _ x y] (filter (comp #{'p3'} second) data)]
#_=> [x y])
[1 1]
Here is how I would do it, based on my favorite template project. Please also note that in Clojure strings always use double-quotes like "p1". Single quotes are totally different!
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn vec-has-label
"Returns true iff a vector has the indicated label"
[vec lbl]
(= lbl (nth vec 1)))
(defn vec->x
"Given a vector, return the x value"
[vec]
(nth vec 2))
(defn find-label
[matrix label]
(let [tgt-vecs (filterv #(vec-has-label % label) matrix) ; find all matching vectors
x-vals (mapv vec->x tgt-vecs)] ; extract the x values
x-vals))
The unit tests show the code in action
(dotest
(isnt (vec-has-label '[plate "p1" 0 1] "p0"))
(is (vec-has-label '[plate "p1" 0 1] "p1"))
(is= 9 (vec->x '[plate "p1" 9 1]))
(let [matrix (quote
[[plate "p1" 0 1]
[plate "p2" 0 2]
[plate "p3" 1 1]])]
(is= (find-label matrix "p3")
[1])
))
The unit test show the 2 ways of "quoting" a data structure that contains one or more symbols. This would be unneeded if the redundant plate symbol weren't present.
See also this list of documentation sources.

How can I get the value of a variable from a string in Clojure?

I was doing a small project in clojure and I wonder if there is something like this:
(let [myvar "hello"] (println (read-var "myvar")))
where the "read-var" function finds that there is a variable with the name passed as string and returns it's value.
I found this load-string function but it seems that doesn't work with let bindings.
Thank you!
I would say that in case you're in need of this kind of behaviour, you're probably not doing it right. in fact i can't even imagine why would someone want to do this in practice
but there is a way
clojure macros have special implicit parameter, called &env, allowing you to get local bindings. So you could use this feature for local vars resolution at runtime:
(defmacro get-env []
(into {} (map (juxt str identity)) (keys &env)))
notice that this macro doesn't require to know your desired var name at compile time, it rather just lifts the bindings from macro scope to runtime scope:
(let [x 10]
(let [y 20]
(get-env)))
;;=> {"x" 10, "y" 20}
(let [a 10
b 20
c 30
env (get-env)]
[a b c env])
;;=> [10 20 30 {"a" 10, "b" 20, "c" 30}]
even this
(let [a 10
b 20
c 30
env (get-env)]
(get-env))
;;=> {"a" 10, "b" 20, "c" 30, "env" {"a" 10, "b" 20, "c" 30}}
(let [x 10] (println ((get-env) "x")))
;;=> 10
;; nil
so the behaviour is dynamic, which could be shown with this fun example:
(defn guess-my-bindings [guesses]
(let [a 10
b 20
c 30]
(mapv #((get-env) % ::bad-luck!) guesses)))
user> (guess-my-bindings ["a" "zee" "c"])
;;=> [10 :user/bad-luck! 30]
but notice that this get-env effect is limited to the bindings effective at it's expand-time. e.g:
(let [x 10
y 20
f (fn [] (let [z 30]
(get-env)))]
(f))
;;=> {"x" 10, "y" 20, "z" 30} ;; ok
(def f (let [x 10
y 20]
(fn [] (let [z 30]
(get-env)))))
(f)
;;=> {"x" 10, "y" 20, "z" 30} ;; ok
but
(let [qwe 999]
(f))
;;=> {"x" 10, "y" 20, "z" 30} ;; oops: no qwe binding
I am not aware of some approach to accomplish this if read-var has to be a function. If read-var were a macro and its argument is a string literal it would be possible to implement read-var so that the code that you wrote works. Another approach would be to build a macro read-var that uses eval, but that would also not be possible because eval cannot access local bindings as explained in this answer.
The closest I could come up with that (i) implements read-var as a function and (ii) lets you pass runtime values as arguments to read-var is the following:
(def ^:dynamic context {})
(defmacro with-readable-vars [symbols & body]
`(binding [context (merge context ~(zipmap (map str symbols) symbols))]
~#body))
(defn read-var [varname]
(get context varname))
and you can now use this code like
(let [myvar "hello"]
(with-readable-vars [myvar]
(println (read-var "myvar")))) ;; Prints hello
The difference compared to your code is that you have to declare the variables that should be readable using the with-readable-vars macro. Obviously, you can build another macro that combines let and with-readable-vars if you like:
(defmacro readable-let [bindings & body]
`(let ~bindings
(with-readable-vars ~(vec (take-nth 2 bindings))
~#body)))
(readable-let [myvar "hello"]
(println (read-var "myvar")))
The above code assumes you are not using advanced features such as destructuring for your bindings.
Pretty simple here:
(let [myvar "hello"]
(println myvar))
;=> hello
Please see this sample project, esp. the list of documentation.
If you really want to pass the name of the variable as a string, you will
need the eval function:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[schema.core :as s]
))
(dotest
(let [mydata "hello"]
(is= "hello" mydata) ; works
))
(def myVar "hello") ; creates a Clojure 'Var': tst.demo.coore/myVar
(dotest
; will fail if don't use fully-qualified namespace in string
(let [parsed (clojure.edn/read-string "(println :with-eval tst.demo.core/myVar)")]
(eval parsed)
;=> `:with-eval hello`
))

Clojure metaprogramming dynamically select record (beginner!)

I have a bunch of records (A B C) that implement a protocol P.
I want to write a method which will select one of the types of records, construct it, and then call a method on it.
For example, if I have a list of the records
(def types '(A B C)) I want to do something like (->(first types) 1 2 3)
Well, functions are also values and can be stored in and retrieved from data structures. So you should be able to just store the constructor functions you want to pick from in some convenient format and use them from there. Something like:
(defrecord foo [x y])
(defrecord bar [x y z])
(def constructors [->foo ->bar])
((first constructors) 4 5) ;;=> #user.foo{:x 4, :y 5}
;;or
(apply (second constructors) [20 true :baz]) ;;=> #user.bar{:x 20, :y true, :z :baz}
(-> (second constructors) (apply '(59 -30 false))) ;;=> #user.bar{:x 59, :y -30, :z false}
or you can even skip the data structure entirely:
(defn quxx [n a-map]
((if (< 25 n) map->foo map->bar) a-map))
(quxx 2 {:x 3 :y 9 :z -200}) ;;=> #user.bar{:x 3, :y 9, :z -200}
(quxx 29 {:x 3 :y 9 :z -200}) ;;=> #user.foo{:x 3, :y 9, :z -200}

Clojure Built in Function to access the entire record

(defrecord Sample (x y))
(def check (Sample. 1 2))
(:x check) ;returns 1
If I receive (:x check) as an argument to a function, is there a way to access check? Or, in other words, return
#:user.Sample{:x 1, :y 2}
No, if a function is passed (:x check) as parameter then the value was already evaluated before entering the function, you'll just receive a 1 as value, and you can't retrieve the record it came from.
If you need the record inside the function, why don't you pass check as parameter?
As Óscar described, (:x check) won't work because its result is 1, and '(:x check) won't work because its result is a list containing the keyword :x and the symbol check.
However, instead of using quote you could use the list function:
(defn receiver [arg]
(map class arg))
;; With a quoted list it receives the symbol `check` rather
;; than the Sample record
(receiver '(:x check))
;=> (clojure.lang.Keyword clojure.lang.Symbol)
;; But this way it does receive the Sample
(receiver (list :x check))
;=> (clojure.lang.Keyword user.Sample)
And (list :x check) can be evaluated:
(eval (list :x check))
;=> 1
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval arg)))
(receiver (list :x check))
;=> "received (:x #user.Sample{:x 1, :y 2}); eval'd to: 1"
The reason that quote and list behave so differently is that quote doesn't evaluate it's argument. And, when a list is quoted, that effect is recursive: none of the items in the list are evaluated either.
There's another type of quote, called syntax-quote or backquote (and described on the Clojure.org page about the reader) which allows you to selectively un-quote (i.e. evaluate) items.
(require '[clojure.pprint])
(let [n 1
x :x
c check]
(clojure.pprint/pprint
(vector `(n x c)
`(~n x c)
`(~n ~x c)
`(~n ~x ~c))))
Prints:
[(user/n user/x user/c)
(1 user/x user/c)
(1 :x user/c)
(1 :x {:x 1, :y 2})]
And, actually, I lied a little bit. You could in fact use '(:x check) in this particular case. resolve will return the Var associated with a symbol, and deref (or its # reader macro) will get you the Var's value.
(resolve 'check)
;=> #'user/check
(deref (resolve 'check))
;=> #user.Sample{:x 1, :y 2}
(defn resolve-and-deref-symbols [form]
(map (fn [x] (if (symbol? x)
#(resolve x)
x))
form))
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval (resolve-and-deref-symbols arg))))
(receiver '(:x check))
;=> "received (:x check); eval'd to: 1"
I didn't mention it straight-away because, while it works easily enough in this example, it's not at all appropriate for the general case. (For instance, it won't work with locals, and handling namespaces and nested data structure would be painful).

Get Clojure argument list

I want something that gives me the sequence of actual values passed to a function, similar to the arguments value in a javascript function.
I am aware that I can grab the entire function argument list using
(defn fx [& args]
args)
<= (fx {:a 1} 2)
=> ({:a 1} 2)
But this removes the arity on my function. I want to have something like
(defn fx [{:keys [a]} b]
(MAGIC_FUNCTION_THAT_RETURNS_THE_ARGS_VALUES))
<= (fx {:a 1} 2)
=> ({:a 1} 2)
Is it possible to get a raw sequence of the values passed to a function?
By the time the function body is executed, the parameters have already been destructured. You could define your own defn macro and expose those values. I know Lighttable does this in their Instarepl to show the argument values.
Using argument destruction can help. The following works fine for me (as far as I know, it also works for old versions of clojure).
(defn example [ & [a b :as args]] [a b args])
(example 1 2)
=> [1 2 (1 2)]
The key point is that you can destruct the argument after &. The drawback is that it is possible to call the function with more arguments than expected (for example (example 1 2 3) is a valid invocation. Special care should be taken if this might be a problem.
Note: I came across this question while I was searching for similar feature. I kept digging and using an idea from here and :as as it was suggested in this answer, I found a solution for my problem.
I don't know of a way to do this as you describe, but depending on what you're wanting to do there are some options.
If you're wanting to ensure the function is only called with two arguments, consider a precondition:
(defn fx [& args]
{:pre [(= 2 (count args))]}
args)
user=> (fx 1 2)
(1 2)
user=> (fx 1 2 3)
AssertionError Assert failed: (= 2 (count args)) user/fx (NO_SOURCE_FILE:1)
If you're wanting to keep track of your intended arity of a function, but still have access to a vector of all args, you could add your own metadata:
(defn
^{:my.ns/arglists '([{:keys [a]} b])}
fx [& args]
args)
user=> (fx 1 2)
(1 2)
user=> (-> #'fx meta :my.ns/arglists first)
[{:keys [a]} b]
If you're just wanting access to the destructured values you described and access to an args value, you could use let:
(defn fx [{:keys [a]} b]
(let [args [{:a a} b]]
[a b args]))
user=> (fx {:a 1 :c 3} 2)
[1 2 [{:a 1} 2]]
user=> (fx {:a 1 :c 3} 2 4)
ArityException Wrong number of args (3) passed to: user$fx clojure.lang.AFn.throwArity (AFn.java:437)
You could also do a combination of these.
Not very nice as it requires to pass params as a vector, but seems apt
user.main=> (defn fx [[{:keys [a] :as e} b :as o]] [a b e o])
#'user.main/fx
user.main=> (fx [{:a 1} 2])
[1 2 {:a 1} [{:a 1} 2]]
user.main=>
You can use a macro to bind the arguments to symbol, _args in this example.
(defmacro defn-args [name args & body]
`(defn ~name ~args
(let [~'_args ~args]
~#body)))
You can then use _args in the body of the function to refer to the arguments:
user> (defn-args foo [{:keys [a b]} y z] _args)
user> (foo {:a 1 :b 10} 2 3)
[{:a 1, :b 10} 2 3]
This is the best I could cook up.
(def ^:dynamic *arguments* nil)
(defn unstructure [form]
(cond
(or (vector? form) (map? form)) (gensym)
(= form '&) '&
:else form))
(defmacro bind-args-defn [name args & body]
(let [simple-args (vec (map unstructure args))
i (.lastIndexOf simple-args '&)
[h r] (split-at (if (neg? i) (count simple-args) i) simple-args)
r (drop 1 r)]
`(defn ~name
~simple-args
(binding [*arguments* (lazy-cat ~#(map vector h) ~#r)]
(let [~args *arguments*]
~#body)))))
(bind-args-defn ;;my special val binding defn
silly ;;the name
[{:keys [a]} [b & c] & d] ;;the arg vector
{:vals *arguments* :a a :b b :c c :d d}) ;;the body
Obviously, this does not accept the full set of defn options (metadata, docstring, pre and post, arities, etc) that can be passed to defn, but I think it illustrates the idea.
It works by capturing the args vector, and then creating a simple-args vector of the same length as the original args but with no destructuring; using that as the defn argument vector. It then massages this simple-args vector into a sort of flat vector without &, which it assigns to *arguments*. *arguments* is then destructured using the original args vector. Kind of convoluted, but it does what I want at the moment.
> (silly {:a 1} [2 3 4] 5 6)
{:vals ({:a 1} [2 3 4] 5 6), :a 1, :b 2, :c (3 4), :d (5 6)}