Fork me on GitHub
#beginners
<
2021-06-16
>
inawarminister00:06:17

Is there a way to print the sequence index inside a for function into a string?

(for [n (rest (read-column "resources\\in-file.csv" 0))]
(if (string? n)
(write-check-result (str "line" sequence-index "ok"))
(write-check-result (spec/explain (string? n))))))
how do I acquire the value of sequence-index? Thank you

tws01:06:13

i might try map-indexed instead (tho having a side effect in there seems offputting). but using for, you could always loop n over the count of columns, then use a :let to set the column contents

tws14:06:47

on second look, maybe you can expand your use of spec to just spec the CSV file and validate it.

zackteo04:06:34

What can I do to read a string like "[17877, 56808]\n2205309.80008291\n" ? read-string will only read the first part

alexmiller04:06:25

use read multiple times on a StringReader

seancorfield05:06:35

user=> (require '[clojure.edn :as edn])
nil
user=> (let [input "[17877, 56808]\n2205309.80008291\n"]
(with-in-str input
[17877 56808]
2205309.80008291
nil
user=>
☝️:skin-tone-2: Another option.

alexmiller05:06:55

seems like mostly the same option :)

zackteo05:06:35

Thanks 🙂 This works. But how would I store/hold the value for later use then?

seancorfield05:06:39

@zackteo Do you just want to produce a sequence of things that were read, until you run out?

zackteo05:06:27

That would be good but am thinking more about reading the values and putting them into a map. From which I can send as data to the frontend

seancorfield05:06:09

user=> (let [input "[17877, 56808]\n2205309.80008291\n"]
(with-in-str input
(loop [xs [] x (edn/read {:eof ::done} *in*)]
(if (= ::done x) xs (recur (conj xs x) (edn/read {:eof ::done} *in*))))))
[[17877 56808] 2205309.80008291]
user=>
You can build whatever data structure you want.

zackteo05:06:38

Let me look into that! Thank you! :)

dabrazhe06:06:01

How can I render numbers to have 2 decimals: n.nn ? eg 1.1 should be 1.10, 1 should be 1.00.

tvirolai06:06:47

format is your friend in this: https://clojuredocs.org/clojure.core/format

tvirolai06:06:20

(format "%.2f" 1.1) => "1.10"

👍 3
dabrazhe09:06:25

It becomes a string. Would it be possible for the number to stay a number, like {:strike 41.00 :bid 4.40} ?

tvirolai09:06:22

No, since the trailing zeroes don't carry any information. When printing them, they can be formatted in different ways but not like that

alexmiller11:06:42

You can set scale if you’re using BigDecimals (M suffix on number literals)

👍 2
sb07:06:03

If I have a lookup index, but I would like to use two eg. {"a" {:a "a" :b: "b" ...}} index, not just “a”,.. “b” etc.. so what is the best way/ practice? (from performance view)

solf07:06:50

You mean nested maps?

sb07:06:16

I would like to add Indexes, maybe the juxt example more helpful (I don’t generate in this way the things, but the result is same):

;; Create lookup maps via a specific key

(defn index-by [coll key-fn]
(into {} (map (juxt key-fn identity) coll)))
;; #'user/index-by

(index-by [{:id 1 :name "foo"}
{:id 2 :name "bar"}
{:id 3 :name "baz"}] :id)
;;=> {1 {:name "foo", :id 1},
;;    2 {:name "bar", :id 2},
;;    3 {:name "baz", :id 3}}

(index-by [{:id 1 :name "foo"}
{:id 2 :name "bar"}
{:id 3 :name "baz"}] :name)
;;=> {"foo" {:name "foo", :id 1},
;;    "bar" {:name "bar", :id 2},
;;    "baz" {:name "baz", :id 3}}

sb07:06:46

I would like to use two index, of course I can solve that in some way in clojure, just what is the best?

sb07:06:16

eg {[“a” “b”] {…} [“c” “d”] {…}} I hope in this way more understable

solf07:06:12

I’m not sure if I understand correctly. Something like this?

(index-by [{:id 1 :name "foo"}
{:id 2 :name "bar"}
{:id 3 :name "baz"}]
(juxt :id :name))
;; => {[1 "foo"] {:id 1, :name "foo"},
;;     [2 "bar"] {:id 2, :name "bar"},
;;     [3 "baz"] {:id 3, :name "baz"}}

solf07:06:37

Replacing a simple keyword like :name by (juxt :id :name))

sb07:06:07

Yes, something similar, but I would like to search by first and second argument too (indepently)

sb07:06:23

I would like to find all “bar” in the map

sb07:06:57

of course I can do like map or for cycle to do that.. is there any faster solution?

sb07:06:40

{[1 "foo"] {:id 1, :name "foo"},
;;     [2 "bar"] {:id 2, :name "bar"},
;;     [3 "baz"] {:id 3, :name "baz"}}
-> get all “bar” from map, is that possible in Clojure?

solf07:06:57

Well yeah it’s possible, but it’s not going to be performant

indy07:06:00

Fastest is to just copy the same values for the keys "foo" and "bar" and have it in the same map sort of like how DB indexing is done. References to the values would be efficient but that is place oriented programming which clojure discourages

👍 3
solf07:06:03

we will need to filter

solf07:06:24

I would make multiple indexes yeah

sb07:06:42

Ok, in this case I do it in this way. Thanks!

km08:06:58

Any idea why this doesn't work? ((symbol "+") 2 2) => 2

delaguardo08:06:59

symbols in clojure implement function interface to work as a getter for associative collections: ((symbol "+") {'+ 42} :not-found) ;; => 42

delaguardo08:06:40

in your example it simply tries to look up for symbol '+ in 2 which is not a collection and falls back to return second argument as “not found” ((symbol "+") 2 3) ;; => 3

delaguardo08:06:35

I think you want to resolve the symbol before calling it as a function. For that you could rewrite your expression like that: ((resolve (symbol "+")) 2 2) ;; => 4

3
❤️ 3
km08:06:57

hmm.. ((resolve '+) 2 2) seems to work, but not ((resolve (symbol "+")) 2 2)

delaguardo09:06:46

works for me, what is the output of (resolve (symbol "+"))?

km09:06:33

hmm! it wasn't working in a clojurescript environment. I switched to clojure and it works

km09:06:13

I think my final code will run on clojure, so I should be fine. In clojurescript, however;

(resolve (symbol "+"))
Encountered error when macroexpanding cljs.core/resolve.
AssertionError: Assert failed: Argument to resolve must be a quoted symbol
(core/and (seq? quoted-sym) (= (quote quote) (first quoted-sym)))
cljs.core/resolve (core.cljc:3417)
cljs.core/resolve (core.cljc:3414)
clojure.core/apply (core.clj:671)
clojure.core/apply (core.clj:662)
cljs.analyzer/macroexpand-1*/fn--2641 (analyzer.cljc:3883)
cljs.analyzer/macroexpand-1* (analyzer.cljc:3881)
cljs.analyzer/macroexpand-1* (analyzer.cljc:3868)
cljs.analyzer/macroexpand-1 (analyzer.cljc:3932)
cljs.analyzer/macroexpand-1 (analyzer.cljc:3928)
cljs.analyzer/analyze-seq (analyzer.cljc:3965)
cljs.analyzer/analyze-seq (analyzer.cljc:3945)
cljs.analyzer/analyze-form (analyzer.cljc:4154)
cljs.analyzer/analyze-form (analyzer.cljc:4151)
cljs.analyzer/analyze* (analyzer.cljc:4207)
cljs.analyzer/analyze* (analyzer.cljc:4199)
clojure.lang.MultiFn.invoke (MultiFn.java:234)
java.lang.Thread.run (Thread.java:829)

delaguardo11:06:27

right, because in clojurescript resolve is a macro and accept only quoted symbol.

Sebastian10:06:25

Is there a better way to write this? I want to extract some values from a list of arguments ({arg-name :some-keyword1 :arg-value "somevalue1"} {arg-name :some-keyword2 :arg-value "somevalue2"}), and turn those into key value pairs for a new map {:some-keyword1 somevalue1 :some-keyword2 :somevalue2) . Currently my approach is to extract both values into a vector while mapping over each argument. I then convert it to a map using into. However it does seem like there might be an easier way of converting it to map, without having to create multiple vectors first

(defn get-args-value [args keywords]
(mapv (fn [arg]
(let [arg-name (:arg-name arg)
arg-value (Integer/parseInt (get-in arg [:arg-value :value]))]
(if (contains? keywords arg-name)
[arg-name arg-value]
[])))
args))

(defn get-values [args keywords]
(into {} (get-args-value args keywords)))

Kuldeep Sengar10:06:42

(def datum '({:arg-name :some-keyword1 :arg-value "somevalue1"} {:arg-name :some-keyword2 :arg-value "somevalue2"}))

(reduce (fn [init data] (assoc init (:arg-name data) (:arg-value data))) {} datum)

Sebastian10:06:16

Yea, that might actually do it! Thanks

delaguardo11:06:18

a bit shorter version based on transducers (into {} (map (juxt :arg-name :arg-value)) datum)

🙌 3
ryan11:06:21

Can probably combine function into one, like:

(defn get-args-value [args keywords]
(->> args
(filter #(contains? keywords (:arg-name %)))
(map (juxt :arg-name :arg-value))
(into {})))

Michael Stokley14:06:47

using the medley library:

(def datum '({:arg-name  :some-keyword1
:arg-value "somevalue1"}
{:arg-name  :some-keyword2
:arg-value "somevalue2"}))

(->> datum
(medley.core/index-by :arg-name)
(medley.core/map-vals :arg-value))
;; => {:some-keyword1 "somevalue1", :some-keyword2 "somevalue2"}

olaf11:06:47

shadow-cljs+reagent: App created with https://github.com/reagent-project/reagent-template. 1. I split my code from project.core in src/cljs/project/core.cljs in another different namespace (path src/cljs/project/lib.cljs ns project.lib ). 2. Imported lib from core.cljs as [project.lib :as lib] 3. Changed .edn file as follow

;; shadow.cljs.edn
:builds       {:app {:target     :browser
:output-dir "resources/public/js"
:asset-path "/js"
:modules    {:app {:entries [project.core]}
:lib {:entries [project.lib]}} 
I got this error during shadow-cljs app compilation
[:app] Configuring build.
[:app] Build failure:
two modules without deps, please specify which one is the default
{:a :app, :b :lib}
ExceptionInfo: two modules without deps, please specify which one is the default

olaf11:06:12

I don't know how to declare the deps. Lib is just a library with some functions, core.cljs uses them to display stuff

Michaël Salihi08:06:41

In fact, it's about dependencies between modules, not libs. You can find an depends-on example in the official doc: https://shadow-cljs.github.io/docs/UsersGuide.html#CodeSplitting

🙌 2
John Preston11:06:39

How can I import a Java class at runtime? I have a class which is only present in some environments, so I want to load it and use a static method if it's available, otherwise I want to do something else 🙂

Martín Varela12:06:46

you can import it, like so:

(import java.util.Base64)

Martín Varela12:06:08

Then you can call static methods on it, like so:

(Base64/getDecoder)
;; => #object[java.util.Base64\$Decoder 0x5b577674 "[email protected]"]

Martín Varela12:06:04

If you're not sure whether the class is available, you should wrap that in a try/catch

John Preston12:06:40

I tried that but the compiler blows up with ClassNotFoundException, like it's trying to load the class before runtime

John Preston12:06:02

I might have found a solution using the Reflect API 🤞

Martín Varela12:06:52

I ran it from a REPL, and it works, but maybe it's a macro, in which case what you said makes sense... You can check in clojuredocs,there's an example for loading classes dynamically...

Martín Varela12:06:12

;; For cases when 'import' does not do it for you, i.e. "live-coding"

class-name
bytes
"")))))

;; From that point the dynamically loaded class can be
;; used by the Reflector to invoke constructors, methods and to get fields. 

Martín Varela12:06:27

that example is from the clojuredocs page on import

Martín Varela12:06:37

hope that helps!

John Preston12:06:41

Thanks I'll take a look at this! 😄

👍 3
noisesmith14:06:45

what's that doing that you wouldn't get from

user=> (Class/forName "java.lang.Number")
java.lang.Number

noisesmith14:06:56

I am probably missing something, because to me the one liner literally does what is asked for here but I'm sure the steps the other code takes are important to some use case

dpsutton15:06:24

I suspect it has to do with the fact that the import is at runtime but there are functions that must be compiled that use it.

Yair Taboch15:06:26

i have java iterator and i want to make something like (map my-func java-iterator) is it possible?

jkxyz15:06:35

(map my-func (seq java-iterator)) should work

Yair Taboch15:06:58

Don't know how to create ISeq from: com.mongodb.MongoCursorAdapter 😞 (MongoCursorAdapter implements Cursor which implements Iterator + closable)

dpsutton15:06:59

try iterator-seq

😲 3
Yair Taboch15:06:26

thanks! may i ask what it does?

dpsutton15:06:15

check out (doc iterator-seq)

dpsutton15:06:34

But high level it just turns the results of an iterator into the clojure seq abstraction

Yair Taboch15:06:23

awesome. thanks 🙂

piyer16:06:51

(-> [{:a 1}]
(map :a))

;; expecting it to return (1)

piyer16:06:24

I know (map :a) would return a lazy fn, what is the better way to do this?

noisesmith16:06:25

(map :a) returns a transducing function, not a lazy one

dpsutton16:06:32

i think you need a thread last here

noisesmith16:06:44

-> expands to put the previous line in the first position:

user=> (macroexpand '(-> [foo] (map :a)))
(map [foo] :a)

👍 3
3
dpsutton16:06:51

you're constructing the form (map [{:a 1}] :a)

piyer16:06:23

(->> [{:a 1}]
(map :a))

piyer16:06:30

that works!

piyer16:06:37

dumb mistake

noisesmith16:06:51

@UGJ2DMT2S also, -> and ->> are pretty "dumb" tools, they are form rewrites my favorite example:

user=> (->> (+ a b) (let [a 19 b 23]))
42

🤯 6
noisesmith16:06:12

that's not good code, but the way it should surprise you might show you something about those macros

3
piyer16:06:53

well, I like the pipeline that -> helps me to build, what is a better approach, use comp ?

dpsutton16:06:44

in my head that is officially called the Noisesmith Demonstration

😆 3
noisesmith16:06:47

@UGJ2DMT2S it's fine to use -> / ->> for building pipelines, that is what they are for, but be aware that they are not "chaining" tools per se, they are tools for convolving forms

noisesmith16:06:12

so there are corner cases, and the substitution follows textual rules, not program logic rules

👍 3
noisesmith16:06:21

there are a few very common bugs that arise from treating the arrow macros as if they were semantic (they aren't, they are syntactic) here's a classic:

user=> (macroexpand '(-> foo (fn [x] (frob x))))
(fn* foo ([x] (frob x)))
obviously I wanted to provide foo as an arg to the fn. instead, because of the textual rewrite rules, I just used the symbol foo as the name of a new anonymous function without calling it

piyer16:06:56

so, you would use as-> here?

seancorfield17:06:51

as-> is intended for use inside -> pipelines for occasional steps that have an argument that is not in the first or last position.

seancorfield17:06:45

👍 3
seancorfield17:06:56

And in the case of calling an anonymous function, the common “trick” is to add extra parens:

(-> foo
((fn [x] (frob x))))
although in this case you could simply do
(-> foo
(frob))
(or just (-> foo frob) but I like the parens to make it really clear it’s a fn call)

Jacob Rosenzweig19:06:44

Can someone help me deconstruct the parameters for this function?

(defn draw-board!
"Draw the given board to the canvas."
([id board scale theme] (draw-board! id board scale theme 0))
([id board scale theme y-cutoff]
...))
Is this basically chaining on the second arity definition?

Prashant02:06:24

Second arity is the one expecting more parameters. First arity merely supplies a value for the skipped parameter while calling the function e.g. first arity supplies and hard codes the value for y-cutoff as 0 Consider 0 default value for parameter y-cutoff of function draw-board! . This is the closest in from C#.

Jacob Rosenzweig19:06:39

It reminds me of constructor chaining in C#.

dpsutton19:06:18

there's a three arity version and a four arity version. The three arity just calls the four arity version with a y-cutoff parameter with value 0. It's a common pattern for providing defaults or overridable parameters

Jacob Rosenzweig19:06:33

Yeah we do that a lot at work with classes.

Jacob Rosenzweig19:06:40

We use that instead of DI frameworks.

didibus20:06:21

It's called function overloading, in this case it's done by arity. So sometimes that specific one is called arity overloading. Where you overload the definition of the function to mean different things based on the number of arguments. But often the implementation is shared, and only parameters differ, thus providing defaults for the smaller arity versions. It's a kind of polymorphism.

dpsutton20:06:03

that's an excellent explanation but i do not see how it is polymorphism

noisesmith20:06:10

it's polymorphic by argument count

Antonio Bibiano20:06:56

Hello peeps, i'm moving my first steps in clojure and sometimes I find that it can be useful to know some java concepts to quickly understand an error or do some operation, e.g. (Integer/parseInt "1") might come very quickly to a java developer that know about how Java interop works. So I was wondering if you have any pointers to some java reference material. I can find my way through a large java codebase even, but i'm missing that "working knowledge". Do you think there's any resource like that, also how much java do you think is important to know to be proficient in clojure?

seancorfield21:06:23

If you want to avoid Java interop for turning strings into numbers/data/etc, there’s clojure.edn/read-string which will also read vectors of numbers and various other things.

practicalli-john22:06:40

I'd suggest you dont need more understanding that is covered in the Java interop section of the http://Clojure.org website. https://clojure.org/reference/java_interop Depending what kinds of applications and services, you may not need any Java interop at all. The most common thing I use is the code you mention in your question and only because jetty web server is very fussy about types.

seancorfield20:06:15

Probably the most useful “Java skill” when learning Clojure is reading/understanding stacktraces. Some understanding of classpaths and dependencies is also useful.

seancorfield20:06:17

I’m not sure what you’re after for “some java reference material” tho’? https://clojure.org/reference/java_interop

Antonio Bibiano20:06:51

I was thinking something like a book that i can use to reference java concepts etc. Because many java books that I found are very long and detailed

Antonio Bibiano21:06:14

actually one book, "Java a beginner's guide"

Antonio Bibiano21:06:10

maybe something like the "In a nutshell" series by oreilly?

seancorfield21:06:21

I don’t think you need much Java to become effective in Clojure. Lots of people come to Clojure with zero Java experience.

seancorfield21:06:47

Most Java material is going to be focused on classes, encapsulation, and often mutable member data — none of which is applicable to Clojure.

Antonio Bibiano21:06:55

Understood, that’s nice to hear :)

Antonio Bibiano21:06:00

I guess I’ll keep practicing my clojure and leave this Java stuff for when the need comes

seancorfield21:06:54

The section on clojure.jar is outdated and has an incorrect link (it tries to link to Clojure 1.9 via the 1.7 URL on Maven). And it uses the old “Java API” for calling Clojure — so follow this instead: https://clojure.org/reference/java_interop#_calling_clojure_from_java

alexmiller21:06:55

and this paid course from Eric is probably also very good (but I haven't seen it) https://purelyfunctional.tv/courses/jvm-clojure/

Antonio Bibiano21:06:10

Ah nice, I’ll check these out!

seancorfield21:06:54

The section on clojure.jar is outdated and has an incorrect link (it tries to link to Clojure 1.9 via the 1.7 URL on Maven). And it uses the old “Java API” for calling Clojure — so follow this instead: https://clojure.org/reference/java_interop#_calling_clojure_from_java

seancorfield21:06:00

(and the section showing Java interop by using String and methods on it is outdated too: clojure.string is a better way to work with strings that avoids Java interop)

Michaël Salihi08:06:41

In fact, it's about dependencies between modules, not libs. You can find an depends-on example in the official doc: https://shadow-cljs.github.io/docs/UsersGuide.html#CodeSplitting

🙌 2