"Joy of Clojure" 2 edition. Listing 11.9 about promises - clojure

I'm examining the Listing 11.9 of the named book (p.269 of pdf).
Could anyone explain me how tests value is being set (line [tests all-tests :as results])?
thanks

To set the context of the question for people without The Joy of Clojure (a book I do enjoy btw), the macro in question is:
(defmacro with-promises [[n tasks _ as] & body]
(when as
`(let [tasks# ~tasks
n# (count tasks#)
promises# (take n# (repeatedly promise))]
(dotimes [i# n#]
(dothreads!
(fn []
(deliver (nth promises# i#)
((nth tasks# i#))))))
(let [~n tasks#
~as promises#]
~#body))))
And is used thusly:
(defn run-tests [& all-tests]
(with-promises
[tests all-tests :as results]
(into (TestRun. 0 0 0)
(reduce #(merge-with + %1 %2) {}
(for [r results]
(if #r
{:run 1 :passed 1}
{:run 1 :failed 1}))))))
and the final call to run-tests is like:
(run-tests pass fail fail fail pass)
=> #user.TestRun{:run 5, :passed 2, :failed 3}
Ultimately, the latter part of the macro is doing a let assignment and running the body, so you end up with
(let [tests tasks#
results promises#]
(into (TestRun. 0 0 0)
;; rest of body
In the macro, ~n is unquoting the starting back-tick around the '(let so you can just read it as n which is the first parameter to the macro (well, the first parameter of the vector that is the first parameter to the macro).
This all happens after the macro has setup the promises using the custom dothreads! function that uses a thread pool - non of which is important to understand the macro.
You can determine more about the macro by wrapping it in a (pprint (macroexpand-1 '(with-promises ... which generates something like (I've replaced the auto generated names with something simpler, v1, n1, p1 and i1):
(clojure.core/let
[v1 all-tests
n1 (clojure.core/count v1)
p1 (clojure.core/take n1 (clojure.core/repeatedly clojure.core/promise))]
(clojure.core/dotimes
[i1 n1]
(user/dothreads!
(clojure.core/fn
[]
(clojure.core/deliver
(clojure.core/nth p1 i1)
((clojure.core/nth v1 i1))))))
(clojure.core/let
[tests v1
results p1]
(into
(TestRun. 0 0 0)
;; ... rest of main body
which clearly shows the parameters passed in are used as variables in the final let bindings.
However, in this example usage (i.e. run-tests function), the tests variable isn't actually used in the body of the with-promises call, only results is, so you're right to question it, it simply isn't needed.
Looking at the macro definition, there may be further optimizations for this case, as the tasks# binding doesn't seem to give anything extra than wrapping tasks. At first I wondered if this was about immutability in the dothreads! call, or macro-niceness for providing a closure around the usage, rather than directly using the parameter to the macro.
I tried changing the macro to remove tasks# completely and directly use ~tasks, which seems to still work, and as "tests" isn't a required binding variable in the body of run-tests, you can drop both the n parameter from the macro, and the ~n tasks# part of the final let binding without issue.
Actually after reading it several times it finally dawned on me it's to make the whole vector read like a standard destructuring binding.
EDIT: some more explanation on "tests".
This is just a name, it could be "foo-tests", "foo-bar", because ultimately it's used to define something in a let binding.
Had the run-tests body been something like:
(defn run-tests [& all-tests]
(with-promises
[foo all-tests :as results]
(println "foo was set to" foo)
(into (TestRun. 0 0 0)
;; rest of body
you can see how foo (and results) are just used to ultimately define variables (eck - you know what i mean) that can be used in the body part of the call to the macro. The body being everything after the initial vector [foo all-tests :as results] but in the original code, tests is declared but unused.

tests appears to be a function, so :as puts the result (output) of running tests on all-tests.
(edit:)
Upon careful inspection, the with-promises macro appears to be setting the tests to the count of tests.
From what I'm reading (don't know much about macros), the arguments appear to map ("tests" "all-tests" ":as" "results") -> ("n" "tasks" "_" "as") but what I can't quite get is that would imply when requires a value for results ("as") when we're supposed to be creating it. Anyway, the value of tests is set in the final let of the macro.
This code is far too clever, in my humble opinion. Fogus is a master, but this is not his best work.
(If I'm wrong, hopefully someone will be inspired.)

Related

How can I iterate over a list with a macro?

I am trying to print the documentation for all functions in a given namespace by invoking the following expression in a REPL:
(doseq
[f (dir-fn 'clojure.repl)]
(doc f))
However the invocation of this expression returns nil without printing the documentation to the REPL. I know this might have to do with doc being a macro, but I'm a Clojure novice and am not entirely sure how to understand the problem.
Why does this expression return nil without printing the documentation?
How can this expression be modified so that it prints the documentation for each function in a given namespace?
Thanks!
Update: Combined both provided answers:
(defn ns-docs [ns']
(doseq [[symbol var] (ns-interns ns')]
(newline)
(println symbol)
(print " ")
(println (:doc (meta var)))))
(ns-docs 'clojure.repl)
I would, instead, start here:
The Clojure CheatSheet
ClojureDocs.org
Clojure-Doc.org (similar name, but different)
The API & Reference sections at Clojure.org
Note that doc is in the namespace clojure.repl, which reflects its intended usage (by a human in a repl). Here is some code that will also iterate on a namespace & print doc strings (using a different technique):
(doseq [[fn-symbol fn-var] (ns-interns 'demo.core)]
(newline)
(println fn-symbol)
(println (:doc (meta fn-var))))
where demo.core is the namespace of interest.
Note that ns-interns gives you both a symbol and var like:
fn-symbol => <#clojure.lang.Symbol -main>
fn-var => <#clojure.lang.Var #'demo.core/-main>
The meta function has lots of other info you may want to use someday:
(meta fn-var) =>
<#clojure.lang.PersistentArrayMap
{ :arglists ([& args]),
:doc "The Main Man!",
:line 9, :column 1,
:file "demo/core.clj",
:name -main,
:ns #object[clojure.lang.Namespace 0x14c35a06 "demo.core"]}>
While this probably won't help you with answering your question, the problem of evaluating macro's comes up a lot when you are learning Clojure.
Macros are responsible for the evaluation of their arguments. In this case clojure.repl/doc will ignore the current lexical context and assume that the symbol f that you're giving it is the name of a function you want to see the documentation for. It does this because it's intended to be used at the REPL, and is assuming you wouldn't want to type quotes all the time.
As f doesn't exist, it prints nothing. Then doseq returns nil, since it exists to do something for side effects only - hence starting in do. In order to pass an argument to a macro that refuses to respect the lexical context like this, you need to write the code for each element in the list.
You can do this by hand, or by constructing the code as data, and passing it to eval to execute. You can do this in an imperative style, using doseq:
(doseq [f (ns-interns 'clojure.repl)]
(eval `(doc ~(symbol "clojure.repl" (str (first f))))))
or in a slightly more Clojurey way (which will allow you to see the code that it would execute by removing eval from the end and running it at the REPL):
(->> (ns-interns 'clojure.repl)
(map #(list 'clojure.repl/doc (symbol "clojure.repl" (str (first %)))))
(cons `do)
eval)
In both of these we use quote and syntax-quote to construct some code from the list of symbols reflected from the namespace, and pass it to eval to actually execute it. This page on Clojure's weird characters should point you in the right direction for understanding what's going on here.
This an example of why you shouldn't write macro's, unless you've got no other options. Macro's do not compose, and are often difficult to work with. For a more in depth discussion, Fogus's talk and Christophe Grand's talk are both good talks.
Why does this expression return nil without printing the documentation?
Because the doc macro is receiving the symbol f from your loop, instead of a function symbol directly.
How can this expression be modified so that it prints the documentation for each function in a given namespace?
(defn ns-docs [ns']
(let [metas (->> (ns-interns ns') (vals) (map meta) (sort-by :name))]
(for [m metas :when (:doc m)] ;; you could filter here if you want fns only
(select-keys m [:name :doc]))))
(ns-docs 'clojure.repl)
=>
({:name apropos,
:doc "Given a regular expression or stringable thing, return a seq of all
public definitions in all currently-loaded namespaces that match the
str-or-pattern."}
...
)
Then you can print those maps/strings if you want.

Alternative Clojure Threading Macro

I'm having a little trouble with a threading macro I'm trying to write. I've posted a stripped down version to show what problem I'm having.
(defmacro <->
[v & fs]
`(do
(-> ~v ~#fs)
~v))
The macro is equivalent to the thread first -> macro, but instead of returning the result of the threading operation, it returns the original value it was passed.
The trouble, I'm having is that when I do something like:
(<-> 1
(<-> println)
(<-> println))
I would expect the output to be
1
1
=> 1
but because the macro evaluates outside in, the macroexpand looks like:
(do
(do
(println
(do
(println 1)
1))
(do
(println 1)
1)) 1)
and the result is
1
1
1
=> 1
I can see why this is happening since the macro is evaluated from outside in, but I'm not sure how to fix it so the macro actually works as expected (i.e. evaluating the value v before threading it to the next form).
Your macro expands to a form in which its v argument is evaluated twice. You need to evaluate v only once, and let-bind the result so you can refer to that value later.
(defmacro <-> [v & fs]
(let [$v (gensym "$v_")]
`(let [~$v ~v]
(-> ~$v ~#fs)
~$v)))
Note the use of gensym to generate a fresh symbol.

clojure get args & exprs of received function

My question is: how can I get the args list and expressions of a received function ?
I'm trying to do something like this:
(defn first-fn [[args exprs]]
(println "Args:" args)
(println "Exprs:" exprs))
(first-fn (fn [a b c] (println "something")))
So, first-fn would print:
Args: [a b c]
Exprs: (println "something")
My goal is to create a macro that can use the args list of the received function.
Thank you.
Edit:
Use case:
I'm using compojure https://github.com/weavejester/compojure
You can define routes like this:
(GET "/:id" [id] (body_here id))
But I would like to change the syntax to be:
(defn handler-fn [id] (body_here id))
...
(GET "/:id" handler-fn)
So the handler (body) can be extracted from the routes, and might be reused as well.
I tried to reuse compile-route https://github.com/weavejester/compojure/blob/master/src/compojure/core.clj#L172
(defmacro MY_GET [path fn-src]
(let [fn-fn (second fn-src)
arg-vec (nth fn-src 2)
forms (drop 3 fn-src)]
(compojure.core/compile-route :get path arg-vec forms)))
But when I call:
(MY_GET "/:id" handler-fn)
It says: Don't know how to create ISeq from: clojure.lang.Symbol
You cannot do this with functions, you directly need a macro to do this and even then it is not straight-forward. First, let's explain the difference: macros are basically evaluated at compile-time and the result of this evaluation is then evaluated at run-time. The interesting part is that the evaluation at compile-time gets the literal, unevaluated arguments to the macro as data and not, like normal functions would, the evaluated arguments at run-time. So, your approach cannot work, because at the time first-fn receives it's arguments (at run-time), they are already evaluated -- in your example, first-fn receives nil as arguments. Cf. the documentation at clojure-doc for a much better explanation.
Now, solving your request with a macro requires the macro to parse the arguments (remember: at compile time, code is data) that it receives -- i.e. in your example, it needs to parse the sequence (fn [a b c] (println "something")) that builds up the function call you hand over to it. Probably you would want to cover other cases besides the fn one (e.g. the # short-hand), that's what it makes the problem not straight-forward in the general case.
This parsing could in the end be handled by a normal function parsing, e.g. a sequence. So, try solving a different puzzle first: build a function parse-code-sequence that takes a sequence (that looks like the functions you would hand over) and returns the args and expr -- note the quote (') in front of fn.
user> (parse-code-sequence '(fn [a b c] (println "something")))
{args: [a b c], expr: (println "something")}
Some hints to this: in the example here, which is showing the most used case, the sequence just consists of three elements and you don't need the first one. But the general case is a little bit more complex, cf. the official documentation on fn.
A final remark: when you implement the macro, you need to think about what it resolves to -- just adding the print-statements is easy, but do you also want to evaluate the arguments normally (so your macro becomes something like a debugging aid) or do you want to do something else?
Update to reflect your use-case
Your MY-GET macro is not doing what you think it's doing.
Take a look at the arguments that the macro gets: why do you think it can magically retrieve the function definition of handler-fn, when all that you give as argument to MY_GET is the symbol/var handler-fn? You would need to retrieve the source, but this usually will not be possible (cf. this SO question on retrieving the source of a function definition).
You are also missing a backquote before the call to compile-route: you want the call to compile-route to happen at run-time, not at compile time. Currently, the result of the macro evaluation is the result of the call to compile-route (at compile-time). Take a look at macroexpand which would show you the result of the macro-expansion. Basically, you want the macro to return the call to compile-route.
I don't see any easy way that you could accomplish what you look for. The argument vector of a route definition is defining what needs to be handed over. Even if you extract that to a function definition, compojure still needs to know what to hand over to that function.
Here is an example of what you could do.
(ns xyz
(:require
[tupelo.core :as t]
))
(t/refer-tupelo)
(spyx *clojure-version*)
(defmacro dissect [ fn-src ]
(let [fn-fn (first fn-src)
arg-vec (second fn-src)
forms (drop 2 fn-src) ]
(spyx fn-fn)
(spyx arg-vec)
(spyx forms)
; Here is the return value; ie the transformed code
`(defn my-fn
~arg-vec
(apply + ~arg-vec))))
; show the result
(newline)
(println
(macroexpand-1
'(dissect
(fn [a b c]
(println "the answer is")
42))))
; call it for real
(newline)
(dissect
(fn [a b c]
(println "the answer is")
42))
; use the generated function
(newline)
(spyx (my-fn 1 2 3))
with result:
*clojure-version* => {:major 1, :minor 8, :incremental 0, :qualifier nil}
fn-fn => fn
arg-vec => [a b c]
forms => ((println "the answer is") 42)
(clojure.core/defn tst.clj.core/my-fn [a b c] (clojure.core/apply clojure.core/+ [a b c]))
fn-fn => fn
arg-vec => [a b c]
forms => ((println "the answer is") 42)
(my-fn 1 2 3) => 6
Your project.clj needs the following to make spyx work:
:dependencies [
[tupelo "0.9.11"]

how to apply gensym to each specific variable

I want to write a macro (my-dotimes [x init end] & body) that computes the value of body for x going from init to end-1 in increments of 1. Here you again have to make sure to avoid the "variable capture problem". It should work like this:
user=> (my-dotimes [x 0 4] (print x))
0123nil
my code is :
(defmacro my-dotimes [[x initial end] & body]
`(loop [i# ~initial]
(when (< i# ~end)
~#body
(recur (inc i#))))))
but when I use macroexpand to check it and find:
user=> (macroexpand '(my-dotimes [x 0 4] (println x)))
(loop* [i__4548__auto__ 0] (clojure.core/when (clojure.core/<i__4548__auto__ 4)
(println x)
(recur (clojure.core/inc i__4548__auto__))))
I am wondering how to change
(println x) => (clojure.core/println i__4548__auto__)
Here, you supply the symbol that should be bound to the counter (here x), so you don't need to use gensyms.
Instead of using i#, just introduce the symbol given to you by the user of the macro.
You need gensyms when you introduce new symbols and don't want them to collide with existing symbols.
In Common Lisp, it would make sense to wrap the body with a binding from the user-supplied symbol to the current value of i, using (let ((,x ,i)) ,#body), because the user's code could change the value of the counter during iteration (which could be bad). But here I think you cannot mutate the variable directly, so you don't need to worry about that.
Your second example is:
(defmacro for-loop [[symb ini t change] & body]
`(loop [symb# ~ini]
(if ~t
~#body
(recur ~change))))
First problem: when you expand the body, which might be one or more form, you'll end-up with an if form with many branches instead of 2. You would have for example (if test x1 x2 x3 (recur ...)) if your body contains x1, x2 and x3. You need to wrap bodies in do expressions, with (do ~#body).
Now, the situation is not very different than before: you still have a symbol, given by the user, and you are responsible for establishing the bindings in the macro. Instead of using symb#, which creates a new symbol, completely distinct from symb, just use symb directly.
You could do this for example (untested):
(defmacro for-loop [[symb init test change] &body]
`(loop [~symb ~init]
(if ~test (do ~#body) (recur ~change))))
As long as you use the symbol provided by the caller of your macro, gensyms are not necessary. You need gensyms when you have to create a new variable in the generated code, which requires to have a fresh symbol. For example, you evaluate an expression only once and need a variable to hold its value:
(defmacro dup [expr]
`(let [var# ~expr]
[var# var#]))

In Clojure, how to define a variable named by a string?

Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)