This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-01-22
Channels
- # announcements (28)
- # babashka (77)
- # beginners (122)
- # calva (40)
- # circleci (3)
- # clj-kondo (47)
- # cljs-dev (9)
- # clojure (119)
- # clojure-australia (1)
- # clojure-europe (88)
- # clojure-nl (3)
- # clojure-uk (33)
- # code-reviews (64)
- # core-logic (37)
- # cursive (10)
- # datomic (13)
- # emacs (1)
- # fulcro (4)
- # graalvm (1)
- # graphql (5)
- # helix (4)
- # integrant (25)
- # jobs (1)
- # jobs-rus (1)
- # off-topic (3)
- # pathom (12)
- # random (1)
- # re-frame (48)
- # reagent (1)
- # remote-jobs (1)
- # reveal (1)
- # rewrite-clj (4)
- # ring (6)
- # ring-swagger (1)
- # shadow-cljs (21)
- # sql (8)
- # tools-deps (25)
- # vim (15)
- # xtdb (12)
the difference almost never comes up. from the vals
docs: "Returns a sequence of the map's values, in the same order as (seq map)." and (seq {})
is nil, so it seems to make sense.
some amount of related background can be found at https://clojure.org/reference/lazy
a common mistake when first coming to clojure is to focus too much on specific types whereas idiomatic clojure code tends to focus on interfaces.
for your example, (seq coll)
is used to check if a sequence has remaining items and (empty? coll)
is used to check if the sequence is empty. both of these idioms will work regardless of the underlying concrete type (eg. map, vector, list, nil)
I've got a http://java.io.File object and I want to get the path to the file. is it OK to just call str
on it ?
seems fine. calling (.getPath f)
would also be reasonable
or depending on the use case, (.getCanonicalPath f)
or (.getAbsolutePath f)
All I'm doing is using using me.raynes.fs to split out the filename from the parent folder name, I'm not actually doing any I/O so I think str will be fine. it seems more "string-manipulation-y"
a nice easy question now for you :-) I want to extract a vector containing selected values from a map in a specified order e.g. (select-vals {:name "john" :age 37 :height 186} [:height :name])
==> [186 "john"]
.
I've come up with (defn select-vals [m ks] (reduce #(conj %1 (m %2)) [] ks))
which does the trick but experience has told me that every time I want to write a reduce
there's usually a built-in function I've missed
@tim.j.robinson you were correct there's a function called select-keys
that does that
((juxt :height :name) {:name "john" :age 37 :height 186})
perhaps
juxt takes fns as arguments, and returns a fn. When called it returns a vector whose first element is the result of calling the first fn and so on.
When I was starting with Clojure, juxt was one of those functions that blew my mind 🙂 Actually, it’s pretty straightfoward… just for clarity this would be equivalent to the example above:
((fn [m] [(:height m) (:name m)]) {:name "john" :age 37 :height 186})
This is exactly what juxt does in this case. Returns a function like: (fn [m] [(:height m) (:name m)])Hi, I want to write a method to convert key and value to keyword when I passing HashMap from Java, But it didn't work. The result like this: {a a}. My expect is like this: {:a :a}
(defn keywordize-kv [m]
(println (->> m
(into {})
(let [f (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])]
(walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))
))
)
in the let block you don't use the threaded value at all, you use the original value of m
, the thread also means that you put m into the last position of the let block, i.e. the result of the walk is discarded and you just return the value you had before.
You had the right idea calling into {}
on m because otherwise it's not considered a map and walk won't attempt to traverse it.
(map? (HashMap.))
=> false
so maybe remove the thread at least until you have it working how you want:
(defn keywordize-kv [m]
(let [f (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])]
(walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x))
(into {} m))))
@ULNRSUK8C Thank you. This is worked fine for me. But I am still wondering if I want to use ->> how should I return the value evaluated?
->> is a macro that puts the value of each consecutive form in the last position of the next (->> a b c)
is the same as (c (b a))
. Because of the let block, the meaning of your original code was something like
(let [] (walk (into {} m)) (into {} m))
The easiest way (imo) to use ->> on your code would be to move the let block up to the top level and thread inside it:
(defn keywordize-hashmap [m]
(let [keywordize-entry (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])
keywordize-map #(into {} (map keywordize-entry %))
keywordize (fn [x] (if (map? x) (keywordize-map x) x))]
(->> m
(into {})
(walk/postwalk keywordize))))
Now the macro will produce something like (walk keywordize (into {} m)
which is what you want!
Hope that helps.Hi! first time posting 🙂 I have an issue with Calva where if I evaluate and pretty print a form and the output is several lines, I only see the first (I can see all lines in output.calva-repl). Is there a way to see all lines? I'm running in vscode on WSL2 @viebel
The inline display only shows the first line. You can peek definition to peek into the output/repl without opening it. Welcome to #calva !
avoid hiccup style formats as internal representations, they are nice for people to write, but because the structure is less regular they are annoying to write programs to manipulate
Let's say I have a map where the keys are Characters and the values are vectors or lists. Let's also say I have a list of tuples like (key_in_map, index_in_vector, value)
.
For each tuple I want to update the map by setting value provided in those "coordinates".
What would be the best way to do this other than mutating the map on each iteration (which I'm not sure is even possible)?
If the values in the map are vectors it is a reduce using update-in, if they are lists or seqs it is pain
It is certainly possible to do it with reduce
and the most common way to do that in Clojure doesn't actually mutate the map -- it creates a new map in each step, each of which is nearly the same as the map created in the previous step.
There is a feature called transients that can be used that will actually create a mutable map, and mutate it in each step. That is an optional performance enhancement, and the code to do it looks almost the same as if you are using immutable maps.
yes, the things we put binding forms into are things that create closures
(functions, let, binding, for, loop etc.)
Hi, I'm still new to Clojure and I want to transform a result set from:
[{:provider "A" :rate 10 :channel "C1"}
{:provider "A" :rate 10 :channel "C2"}
{:provider "A" :rate 10 :channel "C3"}
{:provider "B" :rate 20 :channel "C4"}
{:provider "B" :rate 20 :channel "C5"}
{:provider "B" :rate 20 :channel "C6"}]
To:
[{:provider "A" :rate 10 :channels [{:id "C1"} {:id "C2"} {:id "C3"}]}
{:provider "B" :rate 20 :channels [{:id "C4"} {:id "C5"} {:id "C6"}]}]
Since the query is a JOIN, provider
and rate
gets repeated on the result set. I want to group the channels
by those.
I've tried map, reduce, group-by, partition-by but I haven't gotten exactly to where I want yet.
Any pointers?@diego559 I'd start with (group-by :provider ...)
- that nearly fixes it, it's just a bit of massaging after that
nothing in core does it directly, but I think group-by is the shortest path
also, if provider / rate don't match, what happens then?
if they separate, you'd want (group-by (juxt :provider :rate) ...)
I think I did it. Does it look fine? Suggestions on how I can improve? Since I'm probably going to use this model in multiple other queries, I would like to get it right.
(->> (group-by :provider v)
(map (fn [e]
(let [[provider record] e
rate (:rate (first record))
channels (map :channel record)]
{:provider provider :rate rate :channels channels}))))
you aren't getting the :id
keys like in your example
and usually we'd use {:keys [rate]} (first record)
instead of rate (:rate (first record))
or even [{:keys [rate]}] record
but I feel like the implementation detail that the rate always matches the provider is being buried here - if you don't explicitly check, it should at least be documented
I used juxt
like you suggested to be more future proof. Now I need to figure out how to create a map with :id
for the channels.
(->> (group-by (juxt :provider :rate) v)
(map (fn [e]
(let [[[provider rate] record] e
channels (map :channel record)]
{:provider provider :rate rate :channels channels}))))
that should be straightforward with map (fn [x] {:id x})
or (partial hash-map :id)
or even #(hash-map :id %)
I was trying (map #({:id %})
but realized it doesn't work, don't really sure why it differs from (map (fn [x] {:id x}))
@diego559 reading without evaluating is informative - ' does that
user=> '#({:id %})
(fn* [p1__155#] ({:id p1__155#}))
if we rename the arg:
(fn* [x] ({:id x}))
it's a reader macro, using ' shows how it expands without evaluating it - notice how it adds parens around the body
fn has var-args for the body, so an implicit do
#() fills in the fn body as a template, and only uses one spot, so prevents using that implicit do
imagine if #(foo %)
expanded to (fn [x] foo x)
that would be following the same rule we'd need for #({:id %})
to become (fn [x] {:id x})
but it clearly isn't what you want
hmm, can I rewrite this to more idomatic clojure
(defn convert-number-to-collection [number]
(->> number
str (map (comp read-string str))
read-string
is a big powerful thing, here it's probably better to use #(Long/parseLong %)
or just #(Long/parseLong (str %))
and skip the comp call
but then it would not change for example 12
into (1 2 )
what I need @noisesmith
how wouldn't it?
when I do
(defn convert-number-to-collection [number]
(->> number
str
Long/parseLong))
I never mentioned using it outside a lambda
it's a replacement for read-string, not the entire map call
No matching method ParseLong found taking 1 args for class java.lang.Long
(cmd)user=> (defn convert-number-to-collection [number]
(->> number
str
(map #(Long/parseLong (str %)))))
#'user/convert-number-to-collection
(ins)user=> (convert-number-to-collection 12)
(1 2)
Alternatively, you could do something like this:
(->> 123 str (map #(Character/getNumericValue %)))
@roelof also consider this behavior of the read-string version:
)user=> (convert-number-to-collection "1.23")
(1 . 2 3)
@robert.mitchell36 that's a good one - btw map already calls seq
Good catch. I edited it out.
I am reading the Joy of Clojure and on the chapter about Macros, it says that if
is a macro but when I do in the repl (source if)
it says source not found
it's a special form, those are things implemented in the java code of the compiler
user=> (special-symbol? 'if)
true
conceptually it's like a macro (and might have even been one at some point?) - definitely not a macro today
the way it's like a macro is that its body isn't pre-evaluated (even though it's the java code of the compiler managing what's done with the body, rather than a clojure function)
to see an example, maybe the source of and
would help (similar job to if, actually a macro)
or cond
I am trying to get a grasp of symbol resolution in clojure and have yet to understand behaviour of f
(as well as difference to behaviour of g
) below:
(def a 2)
(def b {3 3})
(defn f [x] (- a (first (map - [x]))))
(defn g [x] (b x))
((juxt f g) 3)
;; => [5 3]
(with-redefs [a 7, b {3 12}, - *] ((juxt f g) 3))
;; => [4 12]
It seems that the two occurences of -
inside f are resolved differently -- is that because in head position it is being compiled at definition time?
If so, what differentiates that +
inside f
from b
in g
? Both (ifn? +)
and (ifn? b)
are true for above values..ah, I see, I'll try this out with different functions then
something to keep in mind is with-redefs is not really intended for us outside of things like stubbing/mocking in tests
for a function like (defn f [a] a)
you can imagine a call like (f 1)
gets compiled to something like (.invoke ^clojure.lang.IFn (deref (resolve 'f)) 1)
the var resolution doesn't actually happen everytime, it is resolved once when the class that the code is attached to, which makes things faster, and usually doesn't behave any different from the above.
+ and -, and some other functions in some circumstances behave like macros, and sort of rewrite themselves
yes, I see with str
in place of -
above the behaviour is different
(+ 1 2)
will rewrite itself before compilation to something like (clojure.lang.Numbers/add 1 2)
> it is resolved once when the class that the code is attached to when the class does what?
the compiler then rewrites some static method calls (under circumstances I don't recall) to a simpler series of bytecodes
Thanks for explanation -- very helpful!
It's not that I'd want to sprinkle my code with with-redefs
s and defn
s, just trying to explore how mutable clojure functions are and in what contexts guarantees or assumptions can be broken 🙂
functions aren't mutable at all, what you are mutating are var
s which are kind of like a special kind of pointer or handle that is used for linking code together
when you use def
you are creating a var with a name, and setting the initial thing the var points to the given value, subsequent defs of the same name change what that var points to
If I'm not mistaken, its because of a feature called inlining. You can define functions to be inlined, which will well, inline them.
As you can see here: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L989
Its kind of a hidden feature not really meant for general consumption, and it seems that they kind of reserve the right to break how it works in the future. So best to assume its a behind the scene optimization for core functions.
But basically, when the function is directly called, the compiler inlines the call, as if it was a macro, using similar semantics to macros. But if the function is passed as an argument (higher order) and later used, the function is evaluated normally, as a function.
@U0K064KQV thanks for the details, that makes it quite clear
@U0NCTKEV8 by «mutable» I wanted to express the fact that what one might naïvely consider to be value of, say, (fn [x] (str x))
, can change after evaluation, depending on context (as e.g. inside with-redefs
). Is there a better term for that?
As far as I can see atm (values of) functions are probably best thought of as immutable values which reference other values, with those references being possibly subject to change, and that makes them different from simple immutable values in my understanding.
Currently I can't think of other types of values which would use that kind of implicit referential sharing, but I might very well know too little about clojure atm.
It reminds me of some discussions about Clojure collections allowing one to include mutable objects inside of them, e.g. the vector [1 2 3 a]
after (def a (atom 4))
is a Clojure collection, but I doubt many people would call it an immutable value, or an immutable collection, because it contains an atom.
There is a very real sense in which Clojure functions containing Var references are mutable -- if you mutate what the Var refers to, the behavior of the function can change to something it never could have done before.
Functions themselves are immutable, but the Var that points to them isn't. Does that help to understand it?
When you redef, you're not changing the function, you're changing the function the Var reference points too
I was thinking more about "vars pointing from them" and what exactly should be considered the immutable value of a function -- as in difference between f
and v
here:
(def m {0 1})
(def f (fn [x] (m x)))
(def v [m])
((juxt f v) 0)
;; => [1 {0 1}]
(def m {0 2})
((juxt f v) 0)
;; => [2 {0 1}]
-- changing m
here does not change v
but changes result of evaluating f
.Currently my working model is "function has immutable structure, but everything in its closure is captured by reference", kind of like if we had something like [0 1 2 #always-deref (defn a (atom 4))]
to always deref its contents upon evaluation.
Oh I see what you mean. The difference is that Clojure auto-derefs things, but not inside fn
:
(def m {0 1})
(def f (fn [x] (m x)))
(def v [#'m]) ;; We tell Clojure not to dereference `m` automatically before creating the vector, by asking Clojure to pass us the Var and not the value the Var points too.
(def m {0 2})
(f 0)
;; => 2
@(v 0)
;; => {0 2}
And similarly, you can chose not to capture the Var in the closure, by forcing it to be dereferenced:
(def m {0 1})
(def f (let [m m] (fn [x] (m x)))) ; Since Clojure doesn't deref inside `fn`, we need to deref it outside, and close over the derefed value
(def v [m])
((juxt f v) 0)
;; => [1 {0 1}]
(def m {0 2})
((juxt f v) 0)
;; => [1 {0 1}]
So its not that everything in its closure is captured by reference
, everything is captured as-is. Its that Clojure has triple indirection. The symbol m
points to the Var #'m
which points to the value {0 1}
. So the function does not close over the symbol
, but it closes over the var that the symbol points too.
But when you do [m]
, Clojure will first resolve the value pointed by the symbol 'm
in the current namespace, which is the Var #'m
, and then it will do one more thing (which it doesn't do when inside fn
), it will also deref the Var, so it will get the value it points too which is {0 1}
and it will pass that to the constructor of vector, thus your vector contains: [{0 1}]
. Like I showed in my example, you can prevent this auto-deref of Vars by Clojure by telling it to give you the Var using (var m)
or #'m
.
Thanks for laying it out in detail! And to everyone in this thread -- it's been enlightening 🙂