How can I add an element to an array-map in Clojure? I tried using assoc but it doesn't get added? I essentially want to set a default value of 0 for any missing items in the entry array-map.
(defn create-entry [doc]
(let [entry (assoc doc "id" (str (java.util.UUID/randomUUID)))]
(if (empty? (get entry "foo")) (assoc entry "foo" 0))
(if (empty? (get entry "bar")) (assoc entry "bar" 0))))
Update after comments from Carcigenicate:
(defn entry [doc]
(as-> (assoc doc "id" (str (java.util.UUID/randomUUID))) e
(if (empty? (get e "foo")) (assoc e "foo" 0) e)
(if (empty? (get e "bar")) (assoc e "bar" 0) e)))
(defn create-entry [doc]
(prn (entry doc)))
You need to starting thinking more functional. Note how all the structures you're using are immutable; they themselves can never change. Your second last line makes a copy of entry, but you never do anything with it; it's just thrown out. There are a few ways of dealing with situations like this where you need to transform a structure over a couple steps:
Just use let:
(let [entry (assoc doc "id" (str (java.util.UUID/randomUUID)))
def-foo (if (empty? (get entry "foo")) (assoc entry "foo" 0) entry)]
(if (empty? (get def-foo "bar")) (assoc def-foo "bar" 0) def-foo)))
Note how the last line uses the def-foo copy, instead of the original entry.
Use a threading macro:
; Create a new binding, e, that will hold the result of the previous form
(as-> (assoc doc "id" (str (java.util.UUID/randomUUID))) e
(if (empty? (get e "foo")) (assoc e "foo" 0) e)
(if (empty? (get e "bar")) (assoc e "bar" 0) e))
e is replaced by whatever the previous form evaluated to.
Note though, that if you ever find yourself using get and assoc on the same object, you might want to consider using update instead, which greatly simplifies everything, especially when paired with the -> threading macro:
(-> (assoc doc "id" (str (java.util.UUID/randomUUID)))
(update "foo" #(if (empty? %) 0 %))
(update "bar" #(if (empty? %) 0 %)))
I had to make some assumptions about what your intent was, because your code has an error that I didn't notice until after I had already submitted my answer. In your original code, your ifs don't evaluate to anything when the condition is false. I'm assuming you just don't want to change anything when they're false.
To supplement Carcigenicate's answer, another suggestion:
I'd use merge or assoc on a map of defaults:
(merge {:default-1 123 :default-2 234} {:default-1 "foo"})
=> {:default-1 "foo", :default-2 234}
Note that the order of arguments to merge matters i.e. right-most maps take precedence over left-most maps. Your default map values will only "survive" if they're not overridden by additional map(s).
(def defaults {"foo" 0, "bar" 0})
(defn create-entry [doc]
(assoc defaults "id" (str (java.util.UUID/randomUUID))))
(defn create-entry [doc]
(merge defaults {"id" (str (java.util.UUID/randomUUID))}))
Using assoc in this example has the same effect, and I'd prefer that version.
Related
The following code does not run as I am expecting. I want to be able to identify if foo and bar are empty and respond with an err accordingly else output "hello". However response only occurs when both foo and bar are present.
I'm new to Clojure and so probably missing something.
(defn create-entry [doc]
(let [id (str (java.util.UUID/randomUUID)) timestamp (quot (System/currentTimeMillis) 1000)]
(let [entry (assoc doc "id" id "timestamp" timestamp)]
(if (and (empty? [(get entry "foo") (empty? (get entry "bar")) ])
(response {:err "either foo or bar is required"})
) (prn "hello!")))))
You have some weird bracing issues going on. You stick both calls to get inside a vector, then check if that hard coded vector is empty.
I think you meant for your condition to be something more like:
(and (empty? (get entry "foo"))
(empty? (get entry "bar")))
I know this has been answered, but I thought I would add something here too. This could be better by splitting this up into two functions, one predicate, and call that from your create-entry function.
(defn entry? [entry]
(let [foo (get entry "foo")
bar (get entry "bar")]
(and (some? foo)
(some? bar))))
(defn create-entry [doc]
(let [id (str (UUID/randomUUID)) timestamp (quot (System/currentTimeMillis) 1000)]
(let [entry (assoc doc "id" id "timestamp" timestamp)]
(if (entry? entry)
(prn "hello!")
(response {:err "either foo or bar is required"})))))
I have a case where I would like to create a new instance of a record based on the type of a record instance that is coming as an argument together with a map of attributes.
(defn record-from-instance
[other attrs]
;; Code that creates the new record based on "other"
)
What I have right now is something among the lines:
(defn record-from-instance
[other attrs]
(let [matched (s/split (subs (str (class other)) 6) #"\.")
path (s/join "." (pop matched))
class-name (peek matched)]
((resolve (symbol (str path "/" "map->" class-name))) attrs)))
Is there any other simpler more idiomatic way to do this that I cannot see?
Thanks!
EDIT
To give some more details I am constructing an AST with nodes being records and I am using a zipper to visit and possibly alter / remove parts of the AST. I have an IZipableTreeNode protocol
(defprotocol IZipableTreeNode
(branch? [node])
(children [node])
(make-node [node children]))
Between the different types that implement the IZipableTreeNode is IPersistentMap
IPersistentMap
(branch? [node] true)
(children [node] (seq node))
(make-node [node children]
(let [hmap (into {} (filter #(= (count %) 2)) children)]
(if (record? node)
(record/from-instance node hmap)
hmap)))
When a visitor say deletes a field from a node (or alters it) the make-node gets called with node being the record AST node and children the new key/value pairs (that may not contain some of the fields in node).
I thought clojure.core/empty used to do this. That is, I thought
(defrecord Foo [x])
(empty (Foo. 1))
would return
#user.Foo{:x nil}
But it certainly doesn't do that now: I'm not sure whether that changed or I misremembered. I can't find a super clean way to do this, but I do at least have something better than your approach. The user/map->Foo function you're using is based on the static method generated along with the class, user.Foo/create, and it is somewhat classier to invoke that directly instead, through reflection.
user> ((fn [r attrs]
(.invoke (.getMethod (class r) "create"
(into-array [clojure.lang.IPersistentMap]))
nil, (into-array Object [attrs])))
(Foo. 1) {:x 5})
#user.Foo{:x 5}
However, it occurs to me now you may not need to do any of this! You started with the preconception that the way to meet your goal of "build a new thing based on a previous thing" was to start from scratch, but why do that? As long as the record being passed into your function doesn't have any "extension" fields added onto it (i.e., those not part of the record definition itself), then you can simply use clojure.core/into:
(into (Foo. 1) {:x 5}) ;=> #user.Foo{:x 5}
You could also do this:
(defn clear [record]
(reduce (fn [record k]
(let [without (dissoc record k)]
(if (= (type record) (type without))
without
(assoc record k nil))))
record
(keys record)))
(defn map->record [record m]
(into (clear record) m))
Example:
(defrecord Foo [x y])
(map->record (map->Foo {:x 1 :y 2 :z 3}) {:y 4})
;;=> #example.core.Foo{:x nil, :y 4}
I'm not sure if this would be more efficient or less efficient than #amalloy's reflection approach.
I'm attempting to modify a specific field in a data structure, described below (a filled example can be found here:
[{:fields "There are a few other fields here"
:incidents [{:fields "There are a few other fields here"
:updates [{:fields "There are a few other fields here"
:content "THIS is the field I want to replace"
:translations [{:based_on "Based on the VALUE of this"
:content "Replace with this value"}]}]}]}]
I already have this implemented it in a number of functions, as below:
(defn- translation-content
[arr]
(:content (nth arr (.indexOf (map :locale arr) (env/get-locale)))))
(defn- translate
[k coll fn & [k2]]
(let [k2 (if (nil? k2) k k2)
c ((keyword k2) coll)]
(assoc-in coll [(keyword k)] (fn c))))
(defn- format-update-translation
[update]
(dissoc update :translations))
(defn translate-update
[update]
(format-update-translation (translate :content update translation-content :translations)))
(defn translate-updates
[updates]
(vec (map translate-update updates)))
(defn translate-incident
[incident]
(translate :updates incident translate-updates))
(defn translate-incidents
[incidents]
(vec (map translate-incident incidents)))
(defn translate-service
[service]
(assoc-in service [:incidents] (translate-incidents (:incidents service))))
(defn translate-services
[services]
(vec (map translate-service services)))
Each array could have any number of entries (though the number is likely less than 10).
The basic premise is to replace the :content in each :update with the relevant :translation based on a provided value.
My Clojure knowledge is limited, so I'm curious if there is a more optimal way to achieve this?
EDIT
Solution so far:
(defn- translation-content
[arr]
(:content (nth arr (.indexOf (map :locale arr) (env/get-locale)))))
(defn- translate
[k coll fn & [k2]]
(let [k2 (if (nil? k2) k k2)
c ((keyword k2) coll)]
(assoc-in coll [(keyword k)] (fn c))))
(defn- format-update-translation
[update]
(dissoc update :translations))
(defn translate-update
[update]
(format-update-translation (translate :content update translation-content :translations)))
(defn translate-updates
[updates]
(mapv translate-update updates))
(defn translate-incident
[incident]
(translate :updates incident translate-updates))
(defn translate-incidents
[incidents]
(mapv translate-incident incidents))
(defn translate-service
[service]
(assoc-in service [:incidents] (translate-incidents (:incidents service))))
(defn translate-services
[services]
(mapv translate-service services))
I would start more or less as you do, bottom-up, by defining some functions that look like they will be useful: how to choose a translation from among a list of translations, and how to apply that choice to an update. But I wouldn't make the functions so tiny as yours: the logic is all spread out into a lot of places, and it's not easy to get an overall idea of what is going on. Here are the two functions I'd start with:
(letfn [(choose-translation [translations]
(let [applicable (filter #(= (:locale %) (get-locale))
translations)]
(when (= 1 (count applicable))
(:content (first applicable)))))
(translate-update [update]
(-> update
(assoc :content (or (choose-translation (:translations update))
(:content update)))
(dissoc :translations)))]
...)
Of course you can defn them instead if you'd like, and I suspect many people would, but they're only going to be used in one place, and they're intimately involved with the context in which they're used, so I like a letfn. These two functions are really all the interesting logic; the rest is just some boring tree-traversal code to apply this logic in the right places.
Now to build out the body of the letfn is straightforward, and easy to read if you make your code be the same shape as the data it manipulates. We want to walk through a series of nested lists, updating objects on the way, and so we just write a series of nested for comprehensions, calling update to descend into the right keyspace:
(for [user users]
(update user :incidents
(fn [incidents]
(for [incident incidents]
(update incident :updates
(fn [updates]
(for [update updates]
(translate-update update))))))))
I think using for here is miles better than using map, although of course they are equivalent as always. The important difference is that as you read through the code you see the new context first ("okay, now we're doing something to each user"), and then what is happening inside that context; with map you see them in the other order and it is difficult to keep tack of what is happening where.
Combining these, and putting them into a defn, we get a function that you can call with your example input and which produces your desired output (assuming a suitable definition of get-locale):
(defn translate [users]
(letfn [(choose-translation [translations]
(let [applicable (filter #(= (:locale %) (get-locale))
translations)]
(when (= 1 (count applicable))
(:content (first applicable)))))
(translate-update [update]
(-> update
(assoc :content (or (choose-translation (:translations update))
(:content update)))
(dissoc :translations)))]
(for [user users]
(update user :incidents
(fn [incidents]
(for [incident incidents]
(update incident :updates
(fn [updates]
(for [update updates]
(translate-update update))))))))))
we can try to find some patterns in this task (based on the contents of the snippet from github gist, you've posted):
simply speaking, you need to
1) update every item (A) in vector of data
2) updating every item (B) in vector of A's :incidents
3) updating every item (C) in vector of B's :updates
4) translating C
The translate function could look like this:
(defn translate [{translations :translations :as item} locale]
(assoc item :content
(or (some #(when (= (:locale %) locale) (:content %)) translations)
:no-translation-found)))
it's usage (some fields are omitted for brevity):
user> (translate {:id 1
:content "abc"
:severity "101"
:translations [{:locale "fr_FR"
:content "abc"}
{:locale "ru_RU"
:content "абв"}]}
"ru_RU")
;;=> {:id 1,
;; :content "абв",
;; :severity "101",
;; :translations [{:locale "fr_FR", :content "abc"} {:locale "ru_RU", :content "абв"}]}
then we can see that 1 and 2 are totally similar, so we can generalize that:
(defn update-vec-of-maps [data k f]
(mapv (fn [item] (update item k f)) data))
using it as a building block you can make up the whole data transformation:
(defn transform [data locale]
(update-vec-of-maps
data :incidents
(fn [incidents]
(update-vec-of-maps
incidents :updates
(fn [updates] (mapv #(translate % locale) updates))))))
(transform data "it_IT")
returns what you need.
then you can generalize it further, making the utility function for arbitrary depth transformations:
(defn deep-update-vec-of-maps [data ks terminal-fn]
(if (seq ks)
((reduce (fn [f k] #(update-vec-of-maps % k f))
terminal-fn (reverse ks))
data)
data))
and use it like this:
(deep-update-vec-of-maps data [:incidents :updates]
(fn [updates]
(mapv #(translate % "it_IT") updates)))
I recommend you look at https://github.com/nathanmarz/specter
It makes it really easy to read and update clojure data structures. Same performance as hand-written code, but much shorter.
Is there a clean, idiomatic way to check that all the values of a map are not empty or 0.
If for instance I have the following map
{"id" 10 "Department" "UI Design" "managerid" 4}
What's the cleanest way to iterate over the values of the map and make sure the strings are not empty ("") or nil and the ints/longs are not 0 or nil.
Essentially I'm trying to validate some input before I commit it to the DB. I know I could use libraries like Prismatic/schema but for now I'd like to know how it could be achieved without this.
This map only contains strings and ints/longs but it could contain other types.
Is there a generic way of doing this?
Multimethods can provide elegant solution for given problem:
; for now dispatch is based only on value type
(defmulti valid? (fn [[k v]] (class v)))
(defmethod valid? java.lang.Long [[_ value]] (not (zero? value)))
(defmethod valid? java.lang.String [[_ value]] (not (empty? value)))
(defmethod valid? nil [_] false)
(defmethod valid? :default [_] true) ; valid for rest cases
To check whole map:
(every? valid? your-map)
Examples:
(every? valid? {:a 1 :b 0}) ; false
(every? valid? {:a 1 :b 1}) ; true
(every? valid? {:a 1 :b ""}) ; false
(every? valid? {:a 1 :b "a"}) ; true
(every? valid? {:a 1 :b "a" :c []}) ; true
Few notes:
(not (empty? value)) can be replaced to (not-empty value) or (seq value), but in both cases full value of string will be returned instead of boolean (which still will evaluate to true of course).
You cannot check number or string for nil because nil has its own type. In example above all nil values are considered as invalid. If for some keys nils are acceptable - dispatch function (fn [[k v]] (class v)) should be changed to also take key into account.
This solution is a bit longer than a simple function like
(defn valid? [[k v]]
(cond (string? v) (not (empty? v))
...
:else true))
but it is more maintainable and extensible.
EDIT. As mentioned in comments, idiomatic way is to use (seq coll) instead of (not (empty? coll)) because empty? is defined like (not (seq coll)). You may still want to keep (not (empty? coll)) check to make validation code more explicit and obvious.
I'm looking for an idiomatic way to get dynamically scoped variables in Clojure (or a similar effect) for use in templates and such.
Here is an example problem using a lookup table to translate tag attributes from some non-HTML format to HTML, where the table needs access to a set of variables supplied from elsewhere:
(def *attr-table*
; Key: [attr-key tag-name] or [boolean-function]
; Value: [attr-key attr-value] (empty array to ignore)
; Context: Variables "tagname", "akey", "aval"
'(
; translate :LINK attribute in <a> to :href
[:LINK "a"] [:href aval]
; translate :LINK attribute in <img> to :src
[:LINK "img"] [:src aval]
; throw exception if :LINK attribute in any other tag
[:LINK] (throw (RuntimeException. (str "No match for " tagname)))
; ... more rules
; ignore string keys, used for internal bookkeeping
[(string? akey)] [] )) ; ignore
I want to be able to evaluate the rules (left hand side) as well as the result (right hand side), and need some way to put the variables in scope at the location where the table is evaluated.
I also want to keep the lookup and evaluation logic independent of any particular table or set of variables.
I suppose there are similar issues involved in templates (for example for dynamic HTML), where you don't want to rewrite the template processing logic every time someone puts a new variable in a template.
Here is one approach using global variables and bindings. I have included some logic for the table lookup:
;; Generic code, works with any table on the same format.
(defn rule-match? [rule-val test-val]
"true if a single rule matches a single argument value"
(cond
(not (coll? rule-val)) (= rule-val test-val) ; plain value
(list? rule-val) (eval rule-val) ; function call
:else false ))
(defn rule-lookup [test-val rule-table]
"looks up rule match for test-val. Returns result or nil."
(loop [rules (partition 2 rule-table)]
(when-not (empty? rules)
(let [[select result] (first rules)]
(if (every? #(boolean %) (map rule-match? select test-val))
(eval result) ; evaluate and return result
(recur (rest rules)) )))))
;; Code specific to *attr-table*
(def tagname) ; need these globals for the binding in html-attr
(def akey)
(def aval)
(defn html-attr [tagname h-attr]
"converts to html attributes"
(apply hash-map
(flatten
(map (fn [[k v :as kv]]
(binding [tagname tagname akey k aval v]
(or (rule-lookup [k tagname] *attr-table*) kv)))
h-attr ))))
;; Testing
(defn test-attr []
"test conversion"
(prn "a" (html-attr "a" {:LINK "www.google.com"
"internal" 42
:title "A link" }))
(prn "img" (html-attr "img" {:LINK "logo.png" })))
user=> (test-attr)
"a" {:href "www.google.com", :title "A link"}
"img" {:src "logo.png"}
This is nice in that the lookup logic is independent of the table, so it can be reused with other tables and different variables. (Plus of course that the general table approach is about a quarter of the size of the code I had when I did the translations "by hand" in a giant cond.)
It is not so nice in that I need to declare every variable as a global for the binding to work.
Here is another approach using a "semi-macro", a function with a syntax-quoted return value, that doesn't need globals:
(defn attr-table [tagname akey aval]
`(
[:LINK "a"] [:href ~aval]
[:LINK "img"] [:src ~aval]
[:LINK] (throw (RuntimeException. (str "No match for " ~tagname)))
; ... more rules
[(string? ~akey)] [] )))
Only a couple of changes are needed to the rest of the code:
In rule-match? The syntax-quoted function call is no longer a list:
- (list? rule-val) (eval rule-val)
+ (seq? rule-val) (eval rule-val)
In html-attr:
- (binding [tagname tagname akey k aval v]
- (or (rule-lookup [k tagname] *attr-table*) kv)))
+ (or (rule-lookup [k tagname] (attr-table tagname k v)) kv)))
And we get the same result without globals. (And without dynamic scoping.)
Are there other alternatives to pass along sets of variable bindings declared elsewhere, without the globals required by Clojure's binding?
Is there an idiomatic way of doing this, like Ruby's binding
or Javascript's function.apply(context)?
Update
I was probably making it too complicated, here is what I assume is a more functional implementation of the above - no globals, no evals and no dynamic scoping:
(defn attr-table [akey aval]
(list
[:LINK "a"] [:href aval]
[:LINK "img"] [:src aval]
[:LINK] [:error "No match"]
[(string? akey)] [] ))
(defn match [rule test-key]
; returns rule if test-key matches rule key, nil otherwise.
(when (every? #(boolean %)
(map #(or (true? %1) (= %1 %2))
(first rule) test-key))
rule))
(defn lookup [key table]
(let [[hkey hval] (some #(match % key)
(partition 2 table)) ]
(if (= (first hval) :error)
(let [msg (str (last hval) " at " (pr-str hkey) " for " (pr-str key))]
(throw (RuntimeException. msg)))
hval )))
(defn html-attr [tagname h-attr]
(apply hash-map
(flatten
(map (fn [[k v :as kv]]
(or
(lookup [k tagname] (attr-table k v))
kv ))
h-attr ))))
This version is shorter, simpler and reads better. So I suppose I have no need for dynamic scoping, at least not yet.
Postscript
The "evaluate everyting every time" approach in my update above turned out to be problematic , and I couldn't figure out how to implement all the conditional tests as a multimethod dispatch (although I think it should be possible).
So I ended up with a macro that expands the table to a function and a cond. This retains the flexibility of the original eval implementation, but is more efficient, takes less coding and doesn't need dynamic scoping:
(deftable html-attr [[akey tagname] aval]
[:LINK ["a" "link"]] [:href aval]
[:LINK "img"] [:src aval]
[:LINK] [:ERROR "No match"]
(string? akey) [] ))))
expands into
(defn html-attr [[akey tagname] aval]
(cond
(and
(= :LINK akey)
(in? ["a" "link"] tagname)) [:href aval]
(and
(= :LINK akey)
(= "img" tagname)) [:src aval]
(= :LINK akey) (let [msg__3235__auto__ (str "No match for "
(pr-str [akey tagname])
" at [:LINK]")]
(throw (RuntimeException. msg__3235__auto__)))
(string? akey) []))
I don't know whether this is particularly functional, but it is certainly DSLish (make a microlanguage to simplify repetitive tasks) and Lispy (code as data, data as code), both of which are orthogonal to being functional.
On the original question - how to do dynamic scoping in Clojure - I suppose the answer becomes that the idiomatic Clojure way is to find a reformulation that doesn't need it.
Your approach to the problem doesn't seem to be very functional, and you are using eval too often; this smells like bad design.
Instead of using snippets of code that you pass to eval, why not use proper functions instead? If the variables required are fixed for all of the patterns, you can pass them in directly as arguments; if they are not, you can pass in the bindings as a map.
Your code looks like you are making it harder than it needs to be. I think what you really want is clojure multi-methods. You can use them to better abstract the dispatch table you created in attr-table and you don't need dynamic scoping or globals to make it work.
; helper macro for our dispatcher function
(defmulti html-attr (fn [& args] (take (dec (count args)) args)))
(defmethod html-attr [:LINK "a"]
[attr tagname aval] {:href aval})
(defmethod html-attr [:LINK "img"]
[attr tagname aval] {:src aval})
All very concise and functional without requiring globals or even an attr-table.
USER=> (html-attr :LINK "a" "http://foo.com")
{:href "http://foo.com}
It doesn't do exactly what your does but a little modification and it would.