pprint's docs are kind of a brick wall. If you pprint a map, it comes out on one line like so: {:a "b", :b "c", :d "e"}. Instead, I'd like to be pprinted like this, optionally with commas:
{:a "b"
:b "c"
:d "e"}
How would one do that with pprint?
You can set the *print-right-margin* binding:
Clojure=> (binding [*print-right-margin* 7] (pprint {:a 1 :b 2 :c 3}))
{:a 1,
:b 2,
:c 3}
Not exactly what you're looking for, but it might be enough?
BTW, the best way to figure this out —or at least the approach I took— is to use
Clojure=> (use 'clojure.contrib.repl-utils)
Clojure=> (source pprint)
(defn pprint
"Pretty print object to the optional output writer. If the writer is not provided,
print the object to the currently bound value of *out*."
([object] (pprint object *out*))
([object writer]
(with-pretty-writer writer
(binding [*print-pretty* true]
(write-out object))
(if (not (= 0 (.getColumn #^PrettyWriter *out*)))
(.write *out* (int \newline))))))
nil
Hmmrmmm.. what does with-pretty-writer do to *out*?
Clojure=> (source clojure.contrib.pprint/with-pretty-writer)
(defmacro #^{:private true} with-pretty-writer [base-writer & body]
`(let [new-writer# (not (pretty-writer? ~base-writer))]
(binding [*out* (if new-writer#
(make-pretty-writer ~base-writer *print-right-margin* *print-miser-width*)
~base-writer)]
~#body
(if new-writer# (.flush *out*)))))
nil
Okay, so *print-right-margin* sounds promising...
Clojure=> (source clojure.contrib.pprint/make-pretty-writer)
(defn- make-pretty-writer
"Wrap base-writer in a PrettyWriter with the specified right-margin and miser-width"
[base-writer right-margin miser-width]
(PrettyWriter. base-writer right-margin miser-width))
nil
Also, this is pretty informative:
Clojure=> (doc *print-right-margin*)
-------------------------
clojure.contrib.pprint/*print-right-margin*
nil
Pretty printing will try to avoid anything going beyond this column.
Set it to nil to have pprint let the line be arbitrarily long. This will ignore all
non-mandatory newlines.
nil
Anyway —and perhaps you already knew even this— if you really want to customize the way that pprint works, you can proxy clojure.contrib.pprint.PrettyWriter and pass that down by binding it to *out*. The PrettyWriter class is pretty large and intimidating, so I'm not sure if this was what you originally meant by your "brick wall" comment.
I don't think you can do that, you'll probably need to write your own, something like:
(defn pprint-map [m]
(print "{")
(doall (for [[k v] m] (println k v)))
(print "}"))
Related
I am testing a function in Clojure which takes a map as input and outputs a map to which the field :timestamp (current-timestamp) is added.
I have problems testing for equality as I cannot predict which timestamp will be added by the function.
(is (= output (convert-map input)))
I thought about dissoc-ing the :timestamp from the output of the function but that seems convoluted, so I wonder if there is a better solution.
You could use the fn with-redefs, and make the fn you're using to get the timestamp always return the same timestamp when testing.
(with-redefs [timestamp-fn (constantly "2019-07-28T12:00:00Z")]
(your-fn params))
You can read about it here: https://clojuredocs.org/clojure.core/with-redefs
Clojure's metadata feature was designed with this in mind. It provides a way to store information about some data that is independent of the data itself.
user> (defn convert-map [input]
(with-meta input {:timestamp (clj-time.core/now)}))
#'user/convert-map
user> (convert-map {:a 1 :b 1})
{:a 1, :b 1}
user> (def input {:a 1 :b 1})
#'user/input
user> (def output (convert-map {:a 1 :b 1}))
#'user/output
user> (:timestamp (meta output))
#object[org.joda.time.DateTime 0x29eb7744 "2019-07-25T15:36:16.609Z"]
user> (= input output)
true
This preserves all equality concepts. It is very useful to keep in mind that the metadata is attached to a particular data so if you do something that copies the contents from input into some other data structure then this metadata would not come along as in this example:
user> (meta (merge output {:c 0}))
{:timestamp
#object[org.joda.time.DateTime 0x29eb7744 "2019-07-25T15:36:16.609Z"]}
user> (meta (merge {:c 0} output))
nil
Either remove the timestamp, or provide a way of making (current-timestamp) produce a known value rather than clock time.
I'm trying to write a macro that can be used both in a global and nested way, like so:
;;; global:
(do-stuff 1)
;;; nested, within a "with-context" block:
(with-context {:foo :bar}
(do-stuff 2)
(do-stuff 3))
When used in the nested way, do-stuff should have access to {:foo :bar} set by with-context.
I've been able to implement it like this:
(def ^:dynamic *ctx* nil)
(defmacro with-context [ctx & body]
`(binding [*ctx* ~ctx]
(do ~#body)))
(defmacro do-stuff [v]
`(if *ctx*
(println "within context" *ctx* ":" ~v)
(println "no context:" ~v)))
However, I've been trying to shift the if within do-stuff from runtime to compile-time, because whether do-stuff is being called from within the body of with-context or globally is an information that's already available at compile-time.
Unfortunately, I've not been able to find a solution, because nested macros seem to get expanded in multiple "macro expansion runs", so the dynamic binding of *ctx* (as set within with-context) is not available anymore when do-stuff gets expanded. So this does not work:
(def ^:dynamic *ctx* nil)
(defmacro with-context [ctx & body]
(binding [*ctx* ctx]
`(do ~#body)))
(defmacro do-stuff [v]
(if *ctx*
`(println "within context" ~*ctx* ":" ~v)
`(println "no context:" ~v)))
Any ideas how to accomplish this?
Or is my approach totally insane and there's a pattern for how to pass state in such a way from one macro to a nested one?
EDIT:
The body of with-context should be able to work with arbitrary expressions, not only with do-stuff (or other context aware functions/macros). So something like this should also be possible:
(with-context {:foo :bar}
(do-stuff 2)
(some-arbitrary-function)
(do-stuff 3))
(I'm aware that some-arbitrary-function is about side effects, it might write something to a database for example.)
When the code is being macroexpanded, Clojure computes a fixpoint:
(defn macroexpand
"Repeatedly calls macroexpand-1 on form until it no longer
represents a macro form, then returns it. Note neither
macroexpand-1 nor macroexpand expand macros in subforms."
{:added "1.0"
:static true}
[form]
(let [ex (macroexpand-1 form)]
(if (identical? ex form)
form
(macroexpand ex))))
Any binding you establish during the execution of a macro is no more in place when you exit your macro (this happens inside macroexpand-1). By the time an inner macro is being expanded, the context is long gone.
But, you can call macroexpand directly, in which case the binding are still effective. Note however that in your case, you probably need to call macroexpand-all.
This answer explains the differences between macroexpand and clojure.walk/macroexpand-all: basically, you need to make sure all inner forms are macroexanded.
The source code for macroexpand-all shows how it is implemented.
So, you can implement your macro as follows:
(defmacro with-context [ctx form]
(binding [*ctx* ctx]
(clojure.walk/macroexpand-all form)))
In that case, the dynamic bindings should be visible from inside the inner macros.
I'd keep it simple.
This is solution avoids state in an additional *ctx* variable. I think it is a more functional approach.
(defmacro do-stuff
([arg1 context]
`(do (prn :arg1 ~arg1 :context ~context))
{:a 4 :b 5})
([arg1]
`(prn :arg1 ~arg1 :no-context)))
(->> {:a 3 :b 4}
(do-stuff 1)
(do-stuff 2))
output:
:arg1 1 :context {:a 3, :b 4}
:arg1 2 :context {:b 5, :a 4}
there is one more variant to do this, using some macro magic:
(defmacro with-context [ctx & body]
(let [ctx (eval ctx)]
`(let [~'&ctx ~ctx]
(binding [*ctx* ~ctx]
(do ~#body)))))
in this definition we introduce another let binding for ctx. Clojure's macro system would then put it into the &env variable, accessible by the inner macros at compile-time. Notice that we also keep bindings so that inner functions could use it.
now we need to define the function to get the context value from macro's &env:
(defn env-ctx [env]
(some-> env ('&ctx) .init .eval))
and then you can easily define do-stuff:
(defmacro do-stuff [v]
(if-let [ctx (env-ctx &env)]
`(println "within context" ~ctx ":" ~v)
`(println "no context:" ~v)))
in repl:
user> (defn my-fun []
(println "context in fn is: " *ctx*))
#'user/my-fun
user> (defmacro my-macro []
`(do-stuff 100))
#'user/my-macro
user> (with-context {:a 10 :b 20}
(do-stuff 1)
(my-fun)
(my-macro)
(do-stuff 2))
;;within context {:a 10, :b 20} : 1
;;context in fn is: {:a 10, :b 20}
;;within context {:a 10, :b 20} : 100
;;within context {:a 10, :b 20} : 2
nil
user> (do (do-stuff 1)
(my-fun)
(my-macro)
(do-stuff 2))
;;no context: 1
;;context in fn is: nil
;;no context: 100
;;no context: 2
nil
I'm trying to handle following DSL:
(simple-query
(is :category "car/audi/80")
(is :price 15000))
that went quite smooth, so I added one more thing - options passed to the query:
(simple-query {:page 1 :limit 100}
(is :category "car/audi/80")
(is :price 15000))
and now I have a problem how to handle this case in most civilized way. as you can see simple-query may get hash-map as a first element (followed by long list of criteria) or may have no hash-mapped options at all. moreover, I would like to have defaults as a default set of options in case when some (or all) of them are not provided explicite in query.
this is what I figured out:
(def ^{:dynamic true} *defaults* {:page 1
:limit 50})
(defn simple-query [& body]
(let [opts (first body)
[params criteria] (if (map? opts)
[(merge *defaults* opts) (rest body)]
[*defaults* body])]
(execute-query params criteria)))
I feel it's kind of messy. any idea how to simplify this construction?
To solve this problem in my own code, I have a handy function I'd like you to meet... take-when.
user> (defn take-when [pred [x & more :as fail]]
(if (pred x) [x more] [nil fail]))
#'user/take-when
user> (take-when map? [{:foo :bar} 1 2 3])
[{:foo :bar} (1 2 3)]
user> (take-when map? [1 2 3])
[nil [1 2 3]]
So we can use this to implement a parser for your optional map first argument...
user> (defn maybe-first-map [& args]
(let [defaults {:foo :bar}
[maybe-map args] (take-when map? args)
options (merge defaults maybe-map)]
... ;; do work
))
So as far as I'm concerned, your proposed solution is more or less spot on, I would just clean it up by factoring out parser for grabbing the options map (here into my take-when helper) and by factoring out the merging of defaults into its own binding statement.
As a general matter, using a dynamic var for storing configurations is an antipattern due to potential missbehavior when evaluated lazily.
What about something like this?
(defn simple-query
[& body]
(if (map? (first body))
(execute-query (merge *defaults* (first body)) (rest body))
(execute-query *defaults* body)))
Is there any way to reuse a destructuring between multiple methods in a multimethod?
(defmulti foo (fn [x] (:a x)))
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e))
(defmethod foo :2 [a] "")
(defmethod foo :3 [a] "")
Now this is a trivial example, but imagine we have a much more complicated destructuring with nested maps and I want to use it on all my defmethods for foo. How would I do that?
A practical solution would be to only use the keys that you need for each individual method. An important thing to note about destructuring is that you don't have to bind every value in the collection you're destructuring. Let's say every map passed to this multimethod contains the keys :a through :e, but you only need a couple of those keys per method. You could do something like this:
; note: a keyword can act as a function; :a here is equivalent to (fn [x] (:a x))
(defmulti foo :a)
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e))
(defmethod foo :2 [{:keys [b d]}] (str b d))
(defmethod foo :3 [{:keys [c e a]}] (str a c e))
If you have a complicated nested structure and you want to grab specific values, you can just leave out the keys you don't need, or alternatively, depending on your use case, a let binding within the function definition might end up being easier to read. Steve Losh's Caves of Clojure comes to mind -- in writing a roguelike text adventure game from scratch in Clojure, he used nested maps to represent the state of a game. Initially he wrote some of the functions using destructuring to access the inner bits of the "game state" map, e.g.:
(defmethod draw-ui :play [ui {{:keys [tiles]} :world :as game} screen]
...
But then later, he decided to make this code more readable by pulling the destructuring out into a let binding:
(defmethod draw-ui :play [ui game screen]
(let [world (:world game)
tiles (:tiles world)
...
The point is, if you're working with a deeply nested structure and you want to keep your code simple (especially if you're writing a multimethod with several methods taking that same structure as an argument), you may want to avoid using destructuring and just use let bindings to grab the pieces you want. get-in is a good tool for concisely getting values from nested collections. Going back to the Caves of Clojure example, if Steve just needed the tiles, he could have done something like this:
(defmethod draw-ui :play [ui game screen]
(let [tiles (get-in game [:world :tiles])
...
Personally, I find that much easier to read than mucking up the function arguments with {{:keys [tiles]} :world :as game}.
EDIT:
If you really want to avoid having to repeat the destructuring for each multimethod, and you want each method to have the same bindings available, you could write a macro:
(defmulti foo :a)
(defmacro deffoomethod [dispatch-val & body]
`(defmethod foo ~dispatch-val [{:keys [~'a ~'b ~'c ~'d ~'e]}]
~#body))
(deffoomethod 1 (str a b c d e))
(deffoomethod 2 (str b d))
(deffoomethod 3 (str a c e))
(foo {:a 1 :b 2 :c 3 :d 4 :e 5})
;=> "12345"
(foo {:a 2 :b \h :d \i})
;=> "hi"
(foo {:a 3 :b \x :c 0 :d \x :e 0})
;=> "300"
I wouldn't recommend this approach, though, as it breaks macro hygiene. Anyone using this macro has to remember that it binds the symbols a through e to the corresponding keys in the argument, and that could be problematic.
I have an atom that has two parts to it.
(def thing (atom {:queue '() :map {}}))
I want to update both :queue and :map in one atomic stroke, to prevent them from getting off-sync.
Queue individually:
(swap! thing update-in [:queue] (list 1))
(From this question: How to append to a nested list in a Clojure atom?)
Map individually:
(swap! thing assoc-in [:map 1] (:key :value))
(From this question: Using swap to MERGE (append to) a nested map in a Clojure atom?)
How can I do these both within a single swap statement? (assuming that would prevent them from getting off-sync?)
You have one change you want to make, right? And you could write that change as a pure function? All you need to do is write that function, and pass it as the argument to swap!.
(defn take-from-queue [{q :queue, m :map}]
{:queue (rest q), :map (assoc m :new-task (first q))})
(swap! thing take-from-queue)
Where of course I have no idea what you actually want the body of your function to do, so I've made up something that doesn't throw an exception.
Say you have a hash-map atom:
(def m1 (atom {:a "A" :b "B"}))
To change :a and :b at the same time, changing their values to values that are different, say the numbers 1 and 2, use this function:
(defn my-swap! [params]
(swap! m1 (fn [old new] new) params))
, like so:
(my-swap! {:a 1 :b 2}) ;=> {:a 1, :b 2}
And the same effect could be achieved with the following function and execution:
(defn my-multi-swap! [params1 params2]
(swap! m1 (fn [old new1 new2] new2) params1 params2))
(my-multi-swap! {} {:a 1 :b 2}) ;=> {:a 1, :b 2}
Normally reset! is used if you want to ignore the old value. Here we use it:
(defn my-merge-swap! [params]
(swap! m1 (fn [old new] (merge old new)) params))
(my-merge-swap! {:b 3}) ;=> {:a "A", :b 3}
The first parameter to the swap! function is the existing value of the atom, and you must pass in one or more extra parameters, which you can use to give the atom its new value.