beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
babardo 2021-01-22T07:40:19.086400Z

Hello, why? I was expecting empty collection!

(valsย {}) => nil

phronmophobic 2021-01-22T07:46:10.088400Z

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.

๐Ÿ™ 1
phronmophobic 2021-01-22T07:47:29.088800Z

some amount of related background can be found at https://clojure.org/reference/lazy

phronmophobic 2021-01-22T07:51:20.090Z

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.

phronmophobic 2021-01-22T07:53:48.092100Z

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)

Tim Robinson 2021-01-22T07:55:19.093100Z

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 ?

Tim Robinson 2021-01-22T08:04:25.093700Z

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"

phronmophobic 2021-01-22T07:56:50.093200Z

seems fine. calling (.getPath f) would also be reasonable

phronmophobic 2021-01-22T07:58:09.093400Z

or depending on the use case, (.getCanonicalPath f) or (.getAbsolutePath f)

roelof 2021-01-22T09:14:06.094400Z

good morning all

๐Ÿ‘‹ 2
Tim Robinson 2021-01-22T09:24:21.099800Z

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

roelof 2021-01-22T09:26:41.100100Z

for me?? why ??

Mno 2021-01-22T09:28:53.101400Z

@tim.j.robinson you were correct there's a function called select-keys that does that

Mno 2021-01-22T09:29:41.102200Z

Oh.. Not sure about the specified order.. You'd have to call vals after that

Mno 2021-01-22T09:31:50.104Z

You could create a new one with (comp vals select-keys) but it doesn't retain order..

Daniel Stephens 2021-01-22T09:34:36.104600Z

((juxt :height :name) {:name "john" :age 37 :height 186}) perhaps

Daniel Stephens 2021-01-22T09:36:02.104700Z

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.

Daniel Stephens 2021-01-22T09:37:09.105100Z

@tim.j.robinson

Tim Robinson 2021-01-22T09:39:14.105300Z

dang! I wouldn't have found that. yes that's it - thanks ๐Ÿ™‚

๐ŸŽ‰ 1
raspasov 2021-01-22T10:23:43.105600Z

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)])

simongray 2021-01-22T11:04:51.109300Z

juxt is the Spanish inquisition of Clojure

โค๏ธ 1
Yang Xu 2021-01-22T11:05:04.109500Z

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))
                ))
  )

Yang Xu 2021-01-25T03:04:29.233200Z

@dstephensย 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?

Daniel Stephens 2021-01-25T11:23:56.253100Z

->> 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.

Yang Xu 2021-01-26T02:57:09.356Z

Thank you for your detailed explanation.

raspasov 2021-01-22T11:14:55.109700Z

What does your input HashMap look like?

Daniel Stephens 2021-01-22T14:25:58.114400Z

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))))

Yoav Tzfati 2021-01-22T16:07:23.118Z

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

pez 2021-01-22T16:25:20.119800Z

The inline display only shows the first line. You can peek definition to peek into the output/repl without opening it. Welcome to #calva !

โค๏ธ 1
2021-01-22T17:09:31.125200Z

use https://github.com/clojure/data.xml

2021-01-22T17:12:31.128200Z

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

๐Ÿ‘ 1
GGfpc 2021-01-22T18:12:55.132400Z

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)?

2021-01-22T18:13:38.132900Z

It is, and that is the way to do it, using reduce

2021-01-22T18:15:09.135600Z

If the values in the map are vectors it is a reduce using update-in, if they are lists or seqs it is pain

2021-01-22T18:15:34.136Z

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.

2021-01-22T18:16:30.137200Z

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.

evocatus 2021-01-22T18:27:06.138Z

can I use names from outer scope in binding forms? So that they are like closures

2021-01-22T18:30:53.138700Z

yes, the things we put binding forms into are things that create closures

2021-01-22T18:31:05.139Z

(functions, let, binding, for, loop etc.)

2021-01-22T20:33:28.141400Z

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?

2021-01-22T20:34:15.142300Z

@diego559 I'd start with (group-by :provider ...) - that nearly fixes it, it's just a bit of massaging after that

2021-01-22T20:34:33.142700Z

nothing in core does it directly, but I think group-by is the shortest path

2021-01-22T20:35:17.143200Z

also, if provider / rate don't match, what happens then?

2021-01-22T20:35:34.143800Z

if they separate, you'd want (group-by (juxt :provider :rate) ...)

2021-01-22T20:35:35.143900Z

They always do because it's a JOIN, the come from the same record of the same table

2021-01-22T20:35:46.144100Z

OK

2021-01-22T21:02:43.145400Z

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}))))

2021-01-22T21:16:21.145700Z

you aren't getting the :id keys like in your example

2021-01-22T21:16:46.146300Z

and usually we'd use {:keys [rate]} (first record) instead of rate (:rate (first record))

2021-01-22T21:17:00.146600Z

or even [{:keys [rate]}] record

2021-01-22T21:17:36.147300Z

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

2021-01-22T21:19:48.147500Z

Thanks!

2021-01-22T21:22:54.149Z

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})))) 

2021-01-22T21:23:54.149700Z

that should be straightforward with map (fn [x] {:id x}) or (partial hash-map :id) or even #(hash-map :id %)

2021-01-22T21:30:35.150800Z

I was trying (map #({:id %}) but realized it doesn't work, don't really sure why it differs from (map (fn [x] {:id x}))

2021-01-22T21:31:35.151300Z

@diego559 reading without evaluating is informative - ' does that

user=> '#({:id %})
(fn* [p1__155#] ({:id p1__155#}))

2021-01-22T21:32:01.151700Z

if we rename the arg:

(fn* [x] ({:id x}))

2021-01-22T21:33:52.152500Z

Sorry, don't really understand what you mean. I thought #() and (fn []) where equivalent

2021-01-22T21:36:53.153100Z

it's a reader macro, using ' shows how it expands without evaluating it - notice how it adds parens around the body

2021-01-22T21:37:10.153400Z

fn has var-args for the body, so an implicit do

2021-01-22T21:37:18.153700Z

#() fills in the fn body as a template, and only uses one spot, so prevents using that implicit do

2021-01-22T21:37:50.154200Z

imagine if #(foo %) expanded to (fn [x] foo x)

2021-01-22T21:38:24.154900Z

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

๐Ÿ‘ 1
dpsutton 2021-01-22T21:41:08.155100Z

that's the best and most clear explanation i've seen for this

โ˜๏ธ 1
2021-01-22T21:41:24.155300Z

๐Ÿป

2021-01-22T21:43:09.155800Z

Makes lots of sense, thanks!

roelof 2021-01-22T21:45:49.156900Z

hmm, can I rewrite this to more idomatic clojure

(defn convert-number-to-collection [number]
  (->> number
       str (map (comp read-string str))

2021-01-22T21:46:51.157700Z

read-string is a big powerful thing, here it's probably better to use #(Long/parseLong %)

2021-01-22T21:47:19.158200Z

or just #(Long/parseLong (str %)) and skip the comp call

roelof 2021-01-22T21:50:10.159Z

but then it would not change for example 12 into (1 2 ) what I need @noisesmith

2021-01-22T21:50:35.159300Z

how wouldn't it?

roelof 2021-01-22T21:51:01.159800Z

when I do

(defn convert-number-to-collection [number]
  (->> number
       str 
       Long/parseLong))

roelof 2021-01-22T21:51:15.160300Z

I get the output 12 instead of (1 2)

2021-01-22T21:51:17.160500Z

I never mentioned using it outside a lambda

2021-01-22T21:51:46.160900Z

it's a replacement for read-string, not the entire map call

roelof 2021-01-22T21:51:50.161100Z

sorry, then I misunderstood you

2021-01-22T21:53:23.161400Z

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)

2021-01-22T21:53:45.162Z

Alternatively, you could do something like this:

(->> 123 str (map #(Character/getNumericValue %)))

2021-01-22T21:53:58.162200Z

@roelof also consider this behavior of the read-string version:

)user=> (convert-number-to-collection "1.23")
(1 . 2 3)

2021-01-22T21:54:11.162600Z

@robert.mitchell36 that's a good one - btw map already calls seq

2021-01-22T21:54:53.162800Z

Good catch. I edited it out.

yiorgos 2021-01-22T21:57:46.164300Z

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

2021-01-22T21:58:55.165Z

it's a special form, those are things implemented in the java code of the compiler

user=> (special-symbol? 'if)
true

2021-01-22T21:59:14.165500Z

conceptually it's like a macro (and might have even been one at some point?) - definitely not a macro today

yiorgos 2021-01-22T21:59:52.165700Z

oh, I see.

yiorgos 2021-01-22T21:59:53.165900Z

thanks

2021-01-22T22:02:13.166600Z

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)

2021-01-22T22:02:49.167100Z

to see an example, maybe the source of and would help (similar job to if, actually a macro)

๐Ÿ‘ 1
2021-01-22T22:03:21.167400Z

or cond

2021-01-22T23:47:59.170500Z

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..

2021-01-22T23:49:42.171300Z

+ and - have some special optimizations to try and make math fast

2021-01-24T03:28:39.196Z

Functions themselves are immutable, but the Var that points to them isn't. Does that help to understand it?

2021-01-24T03:29:09.196200Z

When you redef, you're not changing the function, you're changing the function the Var reference points too

2021-01-24T04:46:27.196400Z

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 .

2021-01-24T05:00:18.197400Z

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.

2021-01-24T06:18:32.209600Z

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}]

2021-01-24T06:37:41.209900Z

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.

๐Ÿ‘ 1
2021-01-24T06:57:38.210300Z

Thanks for laying it out in detail! And to everyone in this thread -- it's been enlightening ๐Ÿ™‚

2021-01-22T23:51:01.171800Z

ah, I see, I'll try this out with different functions then

2021-01-22T23:52:06.172Z

something to keep in mind is with-redefs is not really intended for us outside of things like stubbing/mocking in tests

2021-01-22T23:57:55.172200Z

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)

2021-01-22T23:59:25.172400Z

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.