This Clojure code on GitHub refers to the Unified Update Model.
Could you explain how the fixing function works well with the Unified Update Model?
(defn fixing
"A version of fix that fits better with the unified update model: instead of multiple clauses,
additional args to the transform function are permitted. For example,
(swap! my-atom fixing map? update-in [k] inc)"
[x pred transform & args]
(if ((as-fn pred) x)
(apply (as-fn transform) x args)
x))
The unified update model is the API convention whereby objects of various reference types can be updated in a consistent way, albeit with specialized functions:
;; Atoms
(swap! the-atom f …)
;; Agents
(send the-agent f …)
(send-off the-agent f …)
;; send-via takes an additional initial argument, but otherwise
;; follows the same convention (and of course it's an exact match
;; when partially applied – (partial send-via some-executor))
(send-via executor the-agent f …)
;; Refs
(dosync
(alter the-ref f …)
(commute the-ref f…))
In each case f is the function that should be used to update the value held by the Atom / Agent / Ref, … are additional arguments, if any (e.g. (swap! the-atom f 1 2 3)), and the result of the call is that the reference will atomically assume the value (f old-value …) – although exactly when that will happen with respect to the swap! / alter / send / … call depends on the reference type in question and the update function used.
Here's an example:
(def a (atom 0))
(swap! a - 5)
#a
;= -5
Vars are generally not meant to be used for the same purposes that one might use the above-mentioned reference types for, but they also have an update function with the same contract:
(alter-var-root #'the-var f …)
Finally, the update and update-in functions are worth mentioning in this connection; in effect, they extend the unified update model convention to values – now of course, values are immutable, so calling update or update-in does not result in any object being visibly changed, but the return value is produced similarly as the result of applying an update function to a preexisting value and possibly some extra arguments:
(update {:foo 1} :foo inc)
;= {:foo 2}
The fixing function quoted in the question works better than fix (defined in the same namespace) in the context of UUM update calls, because it can be passed multiple arguments in a way that meshes well with how UUM update functions like swap! work, whereas with fix you'd have to use an anonymous function:
;; the example from the docstring of fixing
(swap! my-atom fixing map? update-in [k] inc)
;; modified to use fix
(swap! my-atom fix map? #(update-in % [k] inc))
Related
I am writing a custom transducer as an exercise, but I am surprised to see that its 0-arity init function is not called.
Why?
Is it related to which aggregation function I am using? If yes, which ones would call the init function and why others are not?
(defn inc-xf [xf]
"inc-xf should be equivalent to (map inc)"
(fn
;; init
([]
(println "init") ;; <- this is not called (???)
(xf))
;; step
([result input]
(println "step" result input)
(xf result (inc input)))
;; completion
([result]
(println "completion" result)
(xf result))))
(transduce inc-xf
+
100
[5 5 5])
If you look at the implementation of transduce you can see what happens.
(defn transduce
;; To get the init value, (f) is used instead of ((xform f))
([xform f coll] (transduce xform f (f) coll))
([xform f init coll]
,,,))
Why, however, is more difficult to answer.
Transducers implementing the zero arity is part of the requirements for a transducer, but it is never actually used in any transducing context in clojure.core. On the mailing list there's been a post asking the same question as you and proposal of an implementation of transduce that actually uses the init arity. The jira ticket was declined, however, with the explanation:
Rich asked me to decline the ticket because the init arity of the xform should not be involved in the reducing function accumulation.
- Alex Miller
Why, then, is the init arity part of the contract for a transducer if it's not used anywhere? ¯\_(ツ)_/¯
How can one use named parameters when running queries using Yesql? For instance, given the following query
-- name: example
select * from table1 where col1=:value1 and col2=:value2
i'd like to use the following code:
(defquery q "query.sql")
(q db {:value1 "A" :value2 "B"})
Right now, Yesql treats the map as a single positional parameter.
Thanks!
The current version of Yesql - 0.4.0 - does not support easily this. The named parameters are only for documentation. You can see them if you do (doc q), but you can't use them to run the query. The author of Yesql has mentioned that they're planning exactly what you want for Yesql 0.5.
What I've done in the same situation is to just manually wrap the query into another function:
(defn q1 [db {:keys [value1 value2]}] (q db value1 value2))
It's a bit cumbersome, but it works.
It is possible to do this automatically even without improving Yesql, but... this is going to be a bit of a hack. You probably do not want to do this.
We can define a function similar to apply that uses the query function's metadata to get the arguments in the right order from the map of named parameters.
(defn apply-with-arglist-fn [f arglist & args]
(let [nargs (butlast args)
kwargs (last args)]
(apply f (concat nargs (map #(get kwargs (keyword %))
(drop (count nargs) arglist))))))
;; Let's define a macro to make calling this a bit easier.
(defmacro apply-with-arglist [f & args]
"Applies fn f to the arguments in a map by matching them with f's
arglist. Works like apply, except that the last parameter should be
a map of keyword arguments. For example:
(defn f [a b c] ...)
(apply-with-arglist f 1 {:b 2 :c 3})
This is equivalent to calling (f 1 2 3)."
`(apply-with-arglist-fn ~f (first (:arglists (meta (var ~f)))) ~#args))
You can use this to run the query:
(apply-with-arglist q db {:value1 "A" :value2 "B"})
Really, though, there should be error handling and dealing with corner cases. A better approach would be to see if you can help the Yesql author to get Yesql 0.5 ready.
First, I have no experience with CS and Clojure is my first language, so pardon if the following problem has a solution, that is immediately apparent for a programmer.
The summary of the question is as follows: one needs to create atoms at will with unknown yet symbols at unknown times. My approach revolves around a) storing temporarily the names of the atoms as strings in an atom itself; b) changing those strings to symbols with a function; c) using a function to add and create new atoms. The problem pertains to step "c": calling the function does not create new atoms, but using its body does create them.
All steps taken in the REPL are below (comments follow code blocks):
user=> (def atom-pool
#_=> (atom ["a1" "a2"]))
#'user/atom-pool
'atom-pool is the atom that stores intermediate to-be atoms as strings.
user=> (defn atom-symbols []
#_=> (mapv symbol (deref atom-pool)))
#'user/atom-symbols
user=> (defmacro populate-atoms []
#_=> (let [qs (vec (remove #(resolve %) (atom-symbols)))]
#_=> `(do ~#(for [s qs]
#_=> `(def ~s (atom #{}))))))
#'user/populate-atoms
'populate-atoms is the macro, that defines those atoms. Note, the purpose of (remove #(resolve %) (atom-symbols)) is to create only yet non-existing atoms. 'atom-symbols reads 'atom-pool and turns its content to symbols.
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(nil nil nil)
Here it is confirmed that there are no 'a1', 'a2', 'a-new' atoms as of yet.
user=> (defn new-atom [a]
#_=> (do
#_=> (swap! atom-pool conj a)
#_=> (populate-atoms)))
#'user/new-atom
'new-atom is the function, that first adds new to-be atom as string to `atom-pool. Then 'populate-atoms creates all the atoms from 'atom-symbols function.
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(#'user/a1 #'user/a2 nil)
Here we see that 'a1 'a2 were created as clojure.lang.Var$Unbound just by defining a function, why?
user=> (new-atom "a-new")
#'user/a2
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(#'user/a1 #'user/a2 nil)
Calling (new-atom "a-new") did not create the 'a-new atom!
user=> (do
#_=> (swap! atom-pool conj "a-new")
#_=> (populate-atoms))
#'user/a-new
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(#'user/a1 #'user/a2 #'user/a-new)
user=>
Here we see that resorting explicitly to 'new-atom's body did create the 'a-new atom. 'a-new is a type of clojure.lang.Atom, but 'a1 and 'a2 were skipped due to already being present in the namespace as clojure.lang.Var$Unbound.
Appreciate any help how to make it work!
EDIT: Note, this is an example. In my project the 'atom-pool is actually a collection of maps (atom with maps). Those maps have keys {:name val}. If a new map is added, then I create a corresponding atom for this map by parsing its :name key.
"The summary of the question is as follows: one needs to create atoms at will with unknown yet symbols at unknown times. "
This sounds like a solution looking for a problem. I would generally suggest you try another way of achieving whatever the actual functionality is without generating vars at runtime, but if you must, you should use intern and leave out the macro stuff.
You cannot solve this with macros since macros are expanded at compile time, meaning that in
(defn new-atom [a]
(do
(swap! atom-pool conj a)
(populate-atoms)))
populate-atoms is expanded only once; when the (defn new-atom ...) form is compiled, but you're attempting to change its expansion when new-atom is called (which necessarily happens later).
#JoostDiepenmaat is right about why populate-atoms is not behaving as expected. You simply cannot do this using macros, and it is generally best to avoid generating vars at runtime. A better solution would be to define your atom-pool as a map of keywords to atoms:
(def atom-pool
(atom {:a1 (atom #{}) :a2 (atom #{})}))
Then you don't need atom-symbols or populate-atoms because you're not dealing with vars at compile-time, but typical data structures at run-time. Your new-atom function could look like this:
(defn new-atom [kw]
(swap! atom-pool assoc kw (atom #{})))
EDIT: If you don't want your new-atom function to override existing atoms which might contain actual data instead of just #{}, you can check first to see if the atom exists in the atom-pool:
(defn new-atom [kw]
(when-not (kw #atom-pool)
(swap! atom-pool assoc kw (atom #{}))))
I've already submitted one answer to this question, and I think that that answer is better, but here is a radically different approach based on eval:
(def atom-pool (atom ["a1" "a2"]))
(defn new-atom! [name]
(load-string (format "(def %s (atom #{}))" name)))
(defn populate-atoms! []
(doseq [x atom-pool]
(new-atom x)))
format builds up a string where %s is substituted with the name you're passing in. load-string reads the resulting string (def "name" (atom #{})) in as a data structure and evals it (this is equivalent to (eval (read-string "(def ...)
Of course, then we're stuck with the problem of only defining atoms that don't already exist. We could change the our new-atom! function to make it so that we only create an atom if it doesn't already exist:
(defn new-atom! [name]
(when-not (resolve (symbol name))
(load-string (format "(def %s (atom #{}))" name name))))
The Clojure community seems to be against using eval in most cases, as it is usually not needed (macros or functions will do what you want in 99% of cases*), and eval can be potentially unsafe, especially if user input is involved -- see Brian Carper's answer to this question.
*After attempting to solve this particular problem using macros, I came to the conclusion that it either cannot be done without relying on eval, or my macro-writing skills just aren't good enough to get the job done with a macro!
At any rate, I still think my other answer is a better solution here -- generally when you're getting way down into the nuts & bolts of writing macros or using eval, there is probably a simpler approach that doesn't involve metaprogramming.
Is there a way to generically get metadata for arguments to a function in clojure? The answer posted in this question does not, actually, work in general:
user> (defn foo "informative dox!" [] 1)
#'user/foo
user> (defmacro get-docs [func] `(:doc (meta (var ~func))))
#'user/get-docs
user> (get-docs foo)
"informative dox!"
user> (get-docs (identity foo))
; Evaluation aborted.
user> (defn process-docs [f] (let [docs (get-docs f)] (reverse docs)))
; Evaluation aborted.
The second-to-last line doesn't work because you can't call var on the list (identity foo), and the last line doesn't even compile because the compiler complains about being unable to resolve f.
Most of the solutions for this problem I've found rely on the idea that you have access to the symbol in the function's definition, or something like that, so that you can do something like (resolve 'f) or (var f). But I want something that I can use on the argument to a function, where you don't know that information.
Essentially, I'd like an expression I can put in place of the question marks below to get the metadata of #'map:
(let [x map] (??? x))
its a mouthful though possible:
(let [x map]
(:doc (meta (second (first (filter #(and (var? (second %))
(= x (var-get (second %))))
(ns-map *ns*)))))))
produces the desired result:
"Returns a lazy sequence consisting of the result of applying f to the
set of first items of each coll, followed by applying f to the set
of second items in each coll, until any one of the colls is\n exhausted. Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments."
under the hood Namespaces are essentially maps of names to vars and the vars contain functions. you can search the contents of these vars for the one that matches the function you are seeking and then look at it's associated var and get the metadata from that var.
conj is used in (conj coll item), for example (conj #{} "Stu").
But, I found this example in 'Programming Clojure' book page16.
(alter visitors conj username)
I guess (conj visitors username) would be the correct usage. What's the secret?
The "secret" is that alter is a special function that is called in a transaction on a ref, and it has the effect of inserting the current value of the ref as the first parameter to whichever function is supplied as its second argument.
In fact the normal usage for conj with a ref would be:
(conj #visitors username)
So alter roughly translates as follows:
(alter vistors conj username)
=> (ref-set visitors (conj #visitors username))
It is not uncommon in Clojure for macros and higher order functions to take a function followed by args and then execute it by inserting a context-dependent argument before the supplied args. This makes caller's life a bit easier. This way you can write:
(alter visitors conj username)
instead of:
(alter visitors #(conj %1 username))
Some other forms that do this are: send,doto,update-in,->,alter-meta!.