What is the built-in Clojure way (if any), to create a single map entry?
In other words, I would like something like (map-entry key value). In other words, the result should be more or less equivalent to (first {key value}).
Remarks:
Of course, I already tried googling, and only found map-entry? However, this document has no linked resources.
I know that (first {1 2}) returns [1 2], which seems a vector. However:
(class (first {1 2}))
; --> clojure.lang.MapEntry
(class [1 2])
; --> clojure.lang.PersistentVector
I checked in the source code, and I'm aware that both MapEntry and PersistentVector extend APersistentVector (so MapEntry is more-or-less also a vector). However, the question is still, whether I can create a MapEntry instance from Clojure code.
Last, but not least: "no, there is no built in way to do that in Clojure" is also a valid answer (which I strongly suspect is the case, just want to make sure that I did not accidentally miss something).
"no, there is no built in way to do that in Clojure" is also a valid answer
Yeah, unfortunately that's the answer. I'd say the best you can do is define a map-entry function yourself:
(defn map-entry [k v]
(clojure.lang.MapEntry/create k v))
Just specify a class name as follows
(clojure.lang.MapEntry. "key" "val")
or import the class to instantiate by a short name
(import (clojure.lang MapEntry))
(MapEntry. "key" "val")
As Rich Hickey says here: "I make no promises about the continued existence of MapEntry. Please don't use it." You should not attempt to directly instantiate an implementation class such clojure.lang.MapEntry. It's better to just use:
(defn map-entry [k v] (first {k v}))
Related
Suppose I've got a function (remove-bad-nodes g) that returns a sequence like this:
[updated-g bad-nodes]
where updated-g is a graph with its bad nodes removed, and bad-nodes is a collection containing the removed nodes.
As an argument to a function or inside a let, I could destructure it like this:
(let [[g bads] (remove-bad-nodes g)]
...)
but that only defines local variables. How could I do that in the REPL, so that in future commands I can refer to the updated graph as g and the removed nodes as bads? The first thing that comes to mind is this:
(def [g bads] (remove-bad-nodes g)
but that doesn't work, because def needs its first argument to be a Symbol.
Note that I'm not asking why def doesn't have syntax like let; there's already a question about that. I'm wondering what is a convenient, practical way to work in the REPL with functions that return "multiple values". If there's some reason why in normal Clojure practice there's no need to destructure in the REPL, because you do something else instead, explaining that might make a useful answer. I've been running into this a lot lately, which is why I'm asking. Usually, but not always, these functions return an updated version of something along with some other information. In side-effecting code, the function would modify the object and return only one value (the removed nodes, in the example), but obviously that's not the Clojurely way to do it.
I think the way to work with such functions in the repl is just to not def your intermediate results unless they are particularly interesting; for interesting-enough intermediate results it's not a big hassle to either def them to a single name, or to write multiple defs inside a destructuring form.
For example, instead of
(def [x y] (foo))
(def [a b] (bar x y))
you could write
(let [[x y] (foo),
[x' y'] (bar x y)])
(def a x') ; or maybe leave this out if `a` isn't that interesting
(def b y'))
A nice side effect of this is that the code you write while playing around in the repl will look much more similar to the code you will one day add to your source file, where you will surely not be defing things over and over, but rather destructuring them, passing them to functions, and so on. It will be easier to adapt the information you learned at the repl into a real program.
There's nothing unique about destructuring w/r/t the REPL. The answer to your question is essentially the same as this question. I think your options are:
let:
(let [[light burnt just-right] (classify-toasts (make-lots-of-toast))]
(prn light burnt just-right))
def the individual values:
(def result (classify-toasts (make-lots-of-toast)))
(def light (nth result 0))
(def burnt (nth result 1))
(def just-right (nth result 2))
Or write a macro to do that def work for you.
You could also consider a different representation if your function is always returning a 3-tuple/vector e.g. you could alternatively return a map from classify-toasts:
{:light 1, :burnt 2, :just-right 3}
And then when you need one of those values, destructure the map using the keywords wherever you need:
(:light the-map) => 1
Observe:
user=> (def results [1 2 3])
#'user/results
user=> (let [[light burnt just-right] results] (def light light) (def burnt burnt) (def just-right just-right))
#'user/just-right
user=> light
1
user=> burnt
2
user=> just-right
3
I've made the same dumb mistake many many times:
(defrecord Record [field-name])
(let [field (:feld-name (->Record 1))] ; Whoops!
(+ 1 field))
Since I misspelled the field name keyword, this will cause a NPE.
The "obvious" solution to this would be to have defrecord emit namespaced keywords instead, since then, especially when working in a different file, the IDE will be able to immediately show what keywords are available as soon as I type ::n/.
I could probably with some creativity create a macro that wraps defrecord that creates the keywords for me, but this seems like overkill.
Is there a way to have defrecord emit namespaced field accessors, or is there any other good way to avoid this problem?
Because defrecords compile to java classes and fields on a java class don't have a concept of namespaces, I don't think there's a good way to have defrecord emit namespaced keywords.
One alternative, if the code is not performance sensitive and doesn't need to implement any protocols and similar, is to just use maps.
Another is, like Alan Thompson's solution, to make a safe-get funtion. The prismatic/plumbing util library also has an implementation of this.
(defn safe-get [m k]
(let [ret (get m k ::not-found)]
(if (= ::not-found ret)
(throw (ex-info "Key not found: " {:map m, :key k}))
ret)))
(defrecord x [foo])
(safe-get (->x 1) :foo) ;=> 1
(safe-get (->x 1) :fo) ;=>
;; 1. Unhandled clojure.lang.ExceptionInfo
;; Key not found:
;; {:map {:foo 1}, :key :fo}
I feel your pain. Thankfully I have a solution that saves me many times/week that I've been using a couple of years. It is the grab function from the Tupelo library. It does not provide the type of IDE integration you are hoping for, but it does provide fail-fast typo-detection, so you always be notified the very first time you try to use the non-existant key. Another benefit is that you'll get a stacktrace showing the line number with the misspelled keyword, not the line number (possibly far, far away) where the nil value causes a NPE.
It also works equally well for both records & plain-old maps (my usual use-case).
From the README:
Map Value Lookup
Maps are convenient, especially when keywords are used as functions to look up a value in a map. Unfortunately, attempting to look up a non-existent keyword in a map will return nil. While sometimes convenient, this means that a simple typo in the keyword name will silently return corrupted data (i.e. nil) instead of the desired value.
Instead, use the function grab for keyword/map lookup:
(grab k m)
"A fail-fast version of keyword/map lookup. When invoked as (grab :the-key the-map),
returns the value associated with :the-key as for (clojure.core/get the-map :the-key).
Throws an Exception if :the-key is not present in the-map."
(def sidekicks {:batman "robin" :clark "lois"})
(grab :batman sidekicks)
;=> "robin"
(grab :spiderman m)
;=> IllegalArgumentException Key not present in map:
map : {:batman "robin", :clark "lois"}
keys: [:spiderman]
The function grab should also be used in place of clojure.core/get. Simply reverse the order of arguments to match the "keyword-first, map-second" convention.
For looking up values in nested maps, the function fetch-in replaces clojure.core/get-in:
(fetch-in m ks)
"A fail-fast version of clojure.core/get-in. When invoked as (fetch-in the-map keys-vec),
returns the value associated with keys-vec as for (clojure.core/get-in the-map keys-vec).
Throws an Exception if the path keys-vec is not present in the-map."
(def my-map {:a 1
:b {:c 3}})
(fetch-in my-map [:b :c])
3
(fetch-in my-map [:b :z])
;=> IllegalArgumentException Key seq not present in map:
;=> map : {:b {:c 3}, :a 1}
;=> keys: [:b :z]
Your other option, using records, is to use the Java-interop style of accessor:
(.field-name myrec)
Since Clojure defrecord compiles into a simple Java class, your IDE may be able to recognize these names more easily. YMMV
I'm working on my first Clojure program. I'm having some issues figuring out how to build a tree based on an input that looks like this:
["A B" "A C" "C D" "D E" "A F" "F G"]
And the output should be something like this:
'(A (B) (C (D (E)) (F (G)))
I'm not sure how to start doing this. When it comes to an imperative programming, for example, I'd use nested loops to find whether this relation already exists or not and when it doesn't, I'd find the parent element and append the child to it. But as far as I know, functional programming would use another approach, one that I would recursively walk all the elements in a vector and in lieu of changing the existent tree I'd built a new one.
I'm not sure whether this works or not, but I have a function that looks like this:
(defn build-tree
[func tree parent child]
(map (fn [i] (if (seq? i)
build-tree
(func i parent child)))))
I'm sure the issue comes from my unfamiliarity with Clojure and functional programming and was hoping someone could explain the best way to use recursion and built this tree.
You are possibly going to receive a few answers much shorter than mine below. I've decided to kind of teach you fish - instead of showing a short program I am going to take you through a systematic way of solving this class of problems. You will have to fill in a few blanks, including converting your data into a more palatable form. These are minor points that will only distract.
The first thing you need to do is break down your output into construction steps. Those steps should match the abstract type your output is representing. In your case the output's concrete type is a list, but it actually represents a tree. These are different abstract types - a list has a head and a tail, that's it, but the tree has nodes, which may have children. You need to think in terms of abstract constructors that build different types of nodes, not about the accidental specific structure you happened to choose to represent your abstract type - a list in your case.
So imagine that you have two constructors that look like
(defn ->branch
[id kids]
...)
(defn ->leaf
[id]
...)
It is of course assumed that every kid is a tree - that is, either a branch or a leaf. In other words, every kid should be a result of either ->branch or ->leaf.
So the only way to build any tree is to have a nested chain of constructor invocations. That's what I mean by "breaking down the output into construction steps." In your case, it means the following chain:
(->branch :A [(->leaf :B) (->branch :C [(->branch :D (->leaf :E))]) (->branch :F [(->leaf :G)])])
(I am going to use keywords instead of symbols for node ids, otherwise we will get bogged down in binding/quoting details.)
Stop here for a second to feel the difference between functional and imperative styles. You outlined the imperative style yourself - you think in terms of updating a tree by finding the right place and adding a new node there. In functional style, you think in terms of creating a value, not updating another value. (Of course nothing technically prevents you from doing the same in an imperative language - like using a nested call to constructors, or using a static factory this way, it's just not something that comes about naturally.)
To get to your specific tree representation as a list, you just need to fill in the implementation of ->branch and ->leaf above, which is very simple. (Left as an exercise for you.)
Now back to building the tree. The task of coding a function that builds a tree is actually creating a chain of constructor calls from the input data. So you need to understand two things:
When to call which constructor (here, when to call ->branch and when call ->leaf)
How to get parameters for the constructors (id for either, and kids for ->branch)
To start, how do we know what node to begin? That depends on what the problem is, but let's assume that it is given us as a parameter. So we assume that we are building the following function:
(defn ->tree
[adj-list node]
...)
The adj-list is your input - which is an adjacency list even if you try to disguise it as a list of strings, and we are going to treat it this way (like #SamEstep suggested in the comments.) Left as an exercise for you to convert your form of input into an adjacency list.
So it should be clear what we use as an id in our constructors - the node. But is it ->branch or ->leaf? Well, the answer depends on whether we have direct descendants of node in the adj-list, so apparently we need a function
(defn descendants
[adj-list node]
...)
which returns a list (possibly empty) of ids of direct descendants of the node. (Left as an exercise.) So we can decide whether to call ->branch or ->leaf depending on whether that list is empty or not, like
(if-let [kid-ids (descendants node)]
(->branch node ...)
(->leaf node))
Ok, then we need to supply these ... to ->branch. Are they kid-ids? No, they must be trees, not ids, either branches or leaves themselves. In other words, we need to first call ->tree on them. See? We hit the recursion point, and it came about naturally (or so I hope). In Clojure, calling a function on every element of a sequence is done by map, which returns a sequence of results, which is exactly what we need:
(if-let [kid-ids (descendants adj-list node)]
(->branch node (map ->tree kid-ids)
(->leaf node))
except that ->tree expects an additional parameter, adj-list. We can use an anonymous function, or we can use partial. We will use a partial with a let binding, which is the cleanest way of doing it:
(let [->tree' (partial ->tree adj-list)]
(if-let [kid-ids (descendants adj-list node)]
(->branch node (map ->tree' kid-ids))
(->leaf node)))
This is it. Let's put it together:
(defn ->tree
[adj-list node]
(let [->tree' (partial ->tree adj-list)]
(if-let [kid-ids (descendants adj-list node)]
(->branch node (map ->tree' kid-ids))
(->leaf node))))
The result:
(def adj-list [[:A :B] [:A :C] [:C :D] [:D :E] [:A :F] [:F :G]])
(->tree adj-list :A)
;; => (:A (:B) (:C (:D (:E))) (:F (:G)))
Let's sum up:
Look at your data in abstract terms. Create constructors, and use them for building your output.
To build output means to create a chain of constructor calls.
Which means you need to map your input's shape to output constructors and their parameters.
In many cases, the recursion will emerge by itself naturally at this step.
After you have done it, you can optimize and short-circuit to your heart's content (like if you look closely, you can do away with ->leaf.) But don't do it prematurely.
Your output looks like an associative structure, is there a reason you're using a list instead of a map here?
Also is the ordering guaranteed to match the tree structure as in your example? I'll assume not. And I think it's easier to not use recursion here...
So let's parse the input into an adjacency list, like:
(reduce
(fn[g edge]
(let [[from to]] (map keyword (str/split " " edge))
(update g from #(conj % to))
{}
["A B" "B C"])
Which should output:
{A [B C F],,,}
which can be used to create your tree as a list if you desire.
I can't test this because I'm in mobile at the moment so forgive any mistakes. :)
Thought user2946753's example was useful. Tweaked it to get it working.
(defn example []
(reduce (fn[g edge]
(let [[from to] (map keyword (str/split edge #" "))]
(update g from #(conj % to))))
{}
["A B" "B C"]))
(example)
=> {:A (:B), :B (:C)}
In Clojure, if I have a function f,
(defn f [& r] ... )
and I have a seq args with the arguments I want to call f with, I can easily use apply:
(apply f args)
Now, say I have another function g, which is designed to take any of a number of optional, named arguments - that is, where the rest argument is destructured as a map:
(defn g [& {:keys [a b] :as m}] ... )
I'd normally call g by doing something like
(g :a 1 :b 2)
but if I happen to have a map my-map with the value {:a 1 :b 2}, and I want to "apply" g to my-map - in other words, get something that would end up as the above call, then I naturally couldn't use apply, since it would be equivalent to
(g [:a 1] [:b 2])
Is there a nice way to handle this? May I have gone off track in my design to end up with this? The best solution I can find would be
(apply g (flatten (seq my-map)))
but I surely don't like it. Any better solutions?
EDIT: A slight improvement to the suggested solution might be
(apply g (mapcat seq my-map))
which at least removes one function call, but it may still not be very clear what's going on.
I have stumbled into this problem myself and ended up defining functions to expect one map. A map can have a variable amount of key/value pairs, and if flexible enough, so there is no need for & rest arguments. Also there is no pain with apply. Makes life a lot easier!
(defn g [{:keys [a b] :as m}] ... )
There is no better direct way than converting to a seq.
You are done. You have done all you can.
It's just not really clojurish to have Common Lisp style :keyword arg functions. If you look around Clojure code you will find that almost no functions are written that way.
Even the great RMS is not a fan of them:
"One thing I don't like terribly much is keyword arguments (8). They don't seem quite Lispy to me; I'll do it sometimes but I minimize the times when I do that." (Source)
At the moment where you have to break a complete hash map into pieces just to pass all of them as keyword mapped arguments you should question your function design.
I find that in the case where you want to pass along general options like :consider-nil true you are probably never going to invoke the function with a hash-map {:consider-nil true}.
In the case where you want to do an evaluation based on some keys of a hash map you are 99% of the time having a f ([m & args]) declaration.
When I started out defining functions in Clojure I hit the same problem. However after thinking more about the problems I tried to solve I noticed myself using destructoring in function declaration almost never.
Here is a very simplistic function which may be used exactly as apply, except that the final arg (which should be a map) will be expanded out to :key1 val1 :key2 val2 etc.
(defn mapply
[f & args]
(apply f (reduce concat (butlast args) (last args))))
I'm sure there are more efficient ways to do it, and whether or not you'd want to end up in a situation where you'd have to use such a function is up for debate, but it does answer the original question. Mostly, I'm childishly satisfied with the name...
Nicest solution I have found:
(apply g (apply concat my-map))
In clojure,
(assoc {})
throws an arity exception, but
(dissoc {})
does not. Why? I would have expected either both of them to throw an exception, or both to make no changes when no keys or values are provided.
EDIT: I see a rationale for allowing these forms; it means we can apply assoc or dissoc to a possibly empty list of arguments. I just don't see why one would be allowed and the other not, and I'm curious as to whether there's a good reason for this that I'm missing.
I personally think the lack of 1-arity assoc is an oversight: whenever a trailing list of parameters is expected (& stuff), the function should normally be capable of working with zero parameters in order to make it possible to apply it to an empty list.
Clojure has plenty of other functions that work correctly with zero arguments, e.g. + and merge.
On the other hand, Clojure has other functions that don't accept zero trailing parameters, e.g. conj.
So the Clojure API is a bit inconsistent in this regard.....
This is not an authoritative answer, but is based on my testing and looking at ClojureDocs:
dissoc 's arity includes your being able to pass in one argument, a map. No key/value is removed from the map, in that case.
(def test-map {:account-no 12345678 :lname "Jones" :fnam "Fred"})
(dissoc test-map)
{:account-no 12345678, :lname "Jones", :fnam "Fred"}
assoc has no similar arity. That is calling assoc requires a map, key, and value.
Now why this was designed this way is a different matter, and if you do not receive an answer with that information -- I hope you do -- then I suggest offering a bounty or go on Clojure's Google Groups and ask that question.
Here is the source.
(defn dissoc
"dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
that does not contain a mapping for key(s)."
{:added "1.0"
:static true}
([map] map)
([map key]
(. clojure.lang.RT (dissoc map key)))
([map key & ks]
(let [ret (dissoc map key)]
(if ks
(recur ret (first ks) (next ks))
ret))))