Fork me on GitHub
#beginners
<
2021-04-12
>
jimmysit000:04:00

I have a lazyseq which contains numbers in pairs, such as (1323 5123) and so on, the thing is, that I was to do a few things, first of: sum that pair into a single one, so for example (+ 1323 5123), but keep in mind there are around 10000 pairs, then I'd like to check which pair, when summed the result is x number, and what was the original pair, any idea?

raspasov00:04:58

Try a combination of map-indexed, filter, first

jimmysit001:04:41

Why map-indexed? doesn't it return a lazyseq too?

jimmysit001:04:46

also, could you explain what you mean, step by step and why?

nmkip01:04:56

maybe something like: `(first (filter #(= x (reduce + %)) pairs))`

jimmysit001:04:48

what is that `pairs` for? keep in mind I already made the pairs

nmkip01:04:12

`pairs` is your lazyseq which contains numbers in pairs

jimmysit001:04:33

ah alright, let me try that code really quick

jimmysit001:04:46

if I'm not wrong, `%` is an empty argument

jimmysit001:04:50

what's the usage here?

nmkip01:04:58

you could also use `some` `(some #(and (= 40 (reduce + %)) %) pairs)`

jimmysit001:04:02

sorry if I make dumb questions, I'm relatively new to clojure

jimmysit001:04:11

and functional programming it self

nmkip01:04:05

`(first (filter #(= x (reduce + %)) pairs))` is the same as `(first (filter (fn [pair] (= x (reduce + pair))) pairs))`

jimmysit001:04:59

well, what you sent doesn't work but it may be an issue with my code it self

jimmysit001:04:26

I'll appreciate any help, here's my code:

``````(ns d1.core
(:require [clojure.math.combinatorics :as combo]))

(require (quote [clojure.string :as str]))

(let [f (slurp "d1num.txt")
u (str/split f #"\s+")
p (combo/selections u 2)
h (map bigint p)]

(first (filter #(= 2 (reduce + %)) h)))``````

jimmysit001:04:00

d1num.txt just contains 200 numbers

nmkip02:04:43

what's the error?

jimmysit002:04:12

Execution error (IllegalArgumentException) No matching ctor found for class java.math.BigInteger

jimmysit002:04:39

looks like it's looking for a constructor

nmkip02:04:37

`(combo/selections u 2)` is returning a lazyseq of pairs right? I haven't used `clojure.math.combinatorics` if that's the case, when you map over p, each element is a sequence. try this:

``````(let [f (slurp "d1num.txt")
u (str/split f #"\s+")
p (map #(BigInteger. %) u)
h (combo/selections p 2)]

(first (filter #(= 2 (reduce + %)) h)))``````

jimmysit002:04:08

and yes, `(combo/selections u 2)` returns a lazyseq of pairs

nmkip02:04:39

try evaluating every step and see if the intermediate results are ok

raspasov02:04:51

@U01TN77V2HJ map-indexed in case you want to know the index of your pair, otherwise not needed

Valentín01:04:43

Hi guys, I have a silly question. I got that re-frame template, I made some changes... how can I deploy that code to heroku?

Azzurite11:04:29

🙌 6
raspasov12:04:30

All of the above sounds about right.

Edward Ciafardini14:04:43

this is a really good answer

pinkfrog01:04:01

How to pronounce assoc and dissoc ?

simongray01:04:16

Assowsh and dissowsh

Azzurite11:04:01

I always say ahsok and dissok

Stuart17:04:09

Yeah me too. Ah-sock and dis-sock, but now i see assowsh that makes much more sense!

hiredman01:04:03

assoc(iate) and dissoc(iate), just don't say the iate

🙃 8
Azzurite11:04:41

ah yes, "a sauce" and "the sauce"

Azzurite11:04:29

🙌 6
finchharold14:04:23

any jackdaw people?

dharrigan14:04:47

There is a #jackdaw channel, perhaps that may help?

pez14:04:11

Why does `map` “cancel” the dynamic binding here?

``````(def ^:dynamic *foo* :FOO)
(defn foo [x] (println "1" *foo*) x)
(binding [*foo* :BAR]
(println "0" *foo*)
(map foo [:foo])) ``````
prints:
``````0 :BAR
1 :FOO``````

mg14:04:06

@pez Likely that's because of laziness. The `map` returns a lazy seq that isn't immediately evaluated - in the REPL it's likely not going to be evaluated until the REPL prints the results, but that happens outside the context of the `binding` call. If you did `(doall (map foo [:foo]))` it should exhibit the behavior you're looking for, as `doall` will force evaluation of the lazy seq immediately.

pez14:04:20

Thanks! That works. I will need to digest this a bit. 😃

pez14:04:01

Actually, in my real usecase, I am not printing, but it still behaves like it “cancel”. But also still, `doall` fixes it. I don’t need the lazyness in my case.

raspasov14:04:41

Perhaps try `run!` instead of `map` (if you don’t need the return values); I also like `mapv`

pez15:04:59

Oh, I do need the return values. 😃

pez15:04:06

So, this is more like what my use case is:

``````(def ^:dynamic *foo* :FOO)
(defn foo [x] [*foo* x])
(binding [*foo* :BAR]
(map foo [1 2 3])) => ([:FOO 1] [:FOO 2] [:FOO 3])``````

pez15:04:23

So, if I understand @michael.gaare correctly, it is the REPL forcing the realisation of the sequence. But it happens at a stage where the `binding` form is out of scope (or whatever is the right term here). Is that correct?

andy.fingerhut15:04:44

`map` and many other Clojure functions are lazy.

andy.fingerhut15:04:24

Until and unless something forces the evaluation of elements of their returned values, the function given to `map`, `foo` in your example, will not be called until you force the evaluation of the elements of the sequence returned from `map`.

andy.fingerhut15:04:40

If you force the evaluation inside of the `binding`, then calls to `foo` will happen then.

andy.fingerhut15:04:44

with the extra bindings

andy.fingerhut15:04:11

if you force the evaluation after the `binding` form has returned, then calls to `foo` will happen then, without the extra bindings in place, because they will have been removed by that time.

andy.fingerhut15:04:43

`binding` and lazy evaluation do not mix well together. Standard realization that all Clojure developers come to when they try to mix the two things.

andy.fingerhut16:04:35

You can either force the evaluation of the lazy sequence(s) inside of the `binding` scope, or not. If you want the extra bindings in place, better force lazy evaluations inside of the `binding` body.

pez16:04:16

Thanks! I think that where I am going with my script, the realization will be forced within the `binding`, but I also need to be able to REPL it in small chunks, so I’ll either get rid of the dynamic variable or stay with `doall`. We’ll see. TIL!

pez15:04:34

I added an example to ClojureDocs now: https://clojuredocs.org/clojure.core/binding#example-60746e7de4b0b1e3652d74c4 , please edit it if it needs clarification. (I don’t dare clarify it yet, because I don’t know if I have understood it correctly.)

Michael Stokley16:04:15

i have a side effecting form that is not idempotent. is there a way to only evaluate it once per repl session? i guess i could set up an atom and flag it as evaluated

Michael Stokley16:04:49

`defer`?

Michael Stokley16:04:47

sorry, meant `delay`

noisesmith16:04:28

yeah, a delay or promise is how I do this

noisesmith16:04:12

delay if it's always the result of the same calculation, promise if various different paths might realize it (eg. different functions for connecting to local / staging / prod resources)

noisesmith16:04:04

@michael740 also consider libs like stuartsierra/component or integrant that are made for managing stateful resources in a systematic and functional way

Michael Stokley16:04:24

can you say a little about choosing between `delay` and `defonce`?

noisesmith16:04:11

if you want the value to be re-inintialized when code reloads, just use delay. if you want the value to only be reinitialized explicitly use delay inside defonce (and use ns-unmap or def to delete the defonce var in order to reload)

noisesmith16:04:59

alternatively use neither delay or defonce, and provide the initialized value as an argument to the code that uses it

noisesmith16:04:11

(which is what component and integrant are for)

Michael Stokley16:04:51

> provide the initialized value as an argument to the code that uses it aka dependency inject?

noisesmith17:04:45

the strict definintion, minus the baggage that all mainstream usage of "dependency injection" carries in tooling / project flow

🙌 3
noisesmith17:04:40

(eg. it's not config driven, its part of your normal code base)

noisesmith17:04:46

I don't use the term when introducing those libs because people with java experience get all the wrong ideas

Michael Stokley17:04:31

right on, makes total sense

mg16:04:50

@michael740 `defonce` could work

Michael Stokley16:04:48

thank you, i'll take a look!

Dave Suico16:04:50

Hey guys, I'm trying to use the library ultra-csv in my polylith project but I keep getting this error FileNotFoundException. How do I install this dependency using VSCode and Calva? thanks!

noisesmith16:04:56

at a glance, be sure that your repl has restarted since the dep was added, and that the dep is in your classpath

noisesmith16:04:25

try `clj -Spath` and see if the dep is in the resulting classpath

hiredman16:04:02

you are adding it as an extra dep when the :dev alias is used, my guess is you aren't using that alias, you should likely move all that up to a toplevel :deps

💯 3
noisesmith16:04:02

oh yeah, contextually having a CSV dep but only at dev time is weird

Dave Suico16:04:47

Hello @hiredman @noisesmith, did I do this right at this time now? I added deps at top level as you said and then I run Calva jack-in but still having the same error

noisesmith17:04:42

that looks right, does "Calva jack-in" actually start a new repl process or just reuse a running one?

Dave Suico17:04:28

I think it is connecting to an existing repl, how do I make it run fresh?

noisesmith17:04:43

sorry, I don't know Calva

Dave Suico17:04:59

unfortunately I don't have clj cli right now since it requires higher version of java, I have to keep an old version in my machine since there are some of my apps that will break if I update to higher version

Dave Suico17:04:27

One weird behavior is when I copy the jack in command and then it starts a new repl server and it works.

noisesmith17:04:29

wait, if you don't have the clj cli, how is the deps.edn config doing anything ?

noisesmith17:04:27

clj is the program that uses deps.edn to start a clojure process (or strictly speaking it's the line editing wrapper over the tool that does that)

Dave Suico17:04:20

I believe Calva and Clojure extensions in VSCode does the heavy lifting. feels weird actually for me as a beginner

noisesmith17:04:33

I would be very surprised if Calva / VSCode replicated or replaced the clj tool

Dave Suico17:04:26

Yeah it's really awesome, btw i fixed it now. I was running the wrong command by connecting to an existing repl instead of running a fresh repl server by calva

pez17:04:17

Calva jack-in will kill any process it has started and start a new one. Connect will just connect to an existing nREPL server.

pez17:04:19

Guessing you are using Windows if you get away without the `clj` tool. To avoid all the different kinds of ways the clojure tools could be installed and need to be started on Windows, Calva bundles borkdude´s `deps.clj`.

noisesmith17:04:27

and `clj -Spath` will verify whether the dep is actually being loaded

piyer18:04:34

is there a way to prevent `lein search` to not return `snapshot` versions?

Dave Suico18:04:40

Hey guys, would I know if a variable is a vector or a list? How would I know their differences when I print it in the repl? thanks!

Michael Stokley18:04:14

to your second question, they print with different data structure literals

Michael Stokley18:04:17

``````(prn '(1 2 3)) ;; => prints (1 2 3)

(prn [1 2 3]) ;; => prints [1 2 3]``````

❤️ 3
Michael Stokley18:04:51

to your first question, you could use `type`

``````(type '(1 2 3))
;; => clojure.lang.PersistentList
(type [1 2 3])
;; => clojure.lang.PersistentVector``````

❤️ 3
raspasov18:04:41

Some list gotchas: ‘(1 2 3) (1 2 3) ss.react.state=> (map inc ‘(1 2 3)) (2 3 4) ss.react.state=> (list? (map inc ‘(1 2 3))) false ss.react.state=> (into ‘() (map inc ‘(1 2 3))) (4 3 2) ss.react.state=> (list? (into ‘() (map inc ’(1 2 3)))) true

❤️ 3
raspasov18:04:35

To check if it’s a list or a vector, use `vector?` and/or `list?`

🎯 3
❤️ 3
raspasov18:04:56

My advice? Stick to vectors 🙂

raspasov18:04:46

[1 2 3] ss.react.state=> (map inc [1 2 3]) (2 3 4) ss.react.state=> (seq? (map inc [1 2 3])) true ss.react.state=> (vector? (map inc [1 2 3])) false ss.react.state=> (list? (map inc [1 2 3])) false ss.react.state=> (into [] (map inc [1 2 3])) [2 3 4] ss.react.state=> (vector? (into [] (map inc [1 2 3]))) true ss.react.state=>

Dave Suico19:04:31

Awesome! Thank you guys I appreciate you all!:thumbsup:

👍 3
👌 3
Michael Stokley18:04:02

what's the general purpose way to apply a macro to a collection (in terms of an arity mismatch)? this question comes up with the macro `or` a lot, and the recommended approach is to use a different (non macro) predicate. but in general, could i use `(eval `(my-macro ~@args))`?

hiredman18:04:40

the real answer is to stop writing macros

Michael Stokley18:04:05

i'm trying to programmatically build up an `s/or` expression

hiredman18:04:32

some day we may get spec2 which is supposed to make that kind of thing easier

hiredman18:04:07

assuming you have a fairly static set of things you want to generate s/or expressions for, I would just codegen it

hiredman18:04:02

run `(do ~@(for [thing things] (make-or thing)))` (but with a syntax quote in front) in the repl then copy and paste it back into the source file

theequalizer7318:04:12

Hi, how can I transform this vector of maps

``````[{:numero  "50588887766"
:mensaje "Lorem ipsum dolor sit amet"}
{:numero "50588997755"
:mensaje "Lorem ipsum dolor sit amet"}]``````
Into this one:
``````[{:clMensajes
{:numero    {:__value "50588887766"},
:mensaje   {:__value "Lorem ipsum dolor sit amet"},
:remitente {:__value "PLIM"}}}
{:clMensajes
{:numero    {:__value "50588997755"}
:mensaje   {:__value "Lorem ipsum dolor sit amet"}
:remitente {:__value "PLIM"}}}]``````
I tried with
``(for [[k v] m] (assoc-in m [k] {:__value v}))``
to solve one part but is not working as I expected

hiredman18:04:00

that isn't valid(you have missing delimiters), so I don't think that is what you tried

hiredman18:04:55

you are splitting the map into a sequence of key value pairs, and then returning an updated version of the original map for each pair

hiredman19:04:25

so making (count m) copies of the original map

theequalizer7319:04:44

The truth is I have no idea how to solve it

Joseph Rollins19:04:50

This goes most of the way:

``````(defn valuize [m] (reduce (fn [acc [k v]] (assoc acc k {:__value v})) {} m))

user=> (valuize (input 0))
{:numero {:__value "50588887766"}, :mensaje {:__value "Lorem ipsum dolor sit amet"}}``````

3
3
Michael Stokley19:04:34

another way to express this, if you don't want to use `reduce`

``````(->> {:numero  "50588887766"
:mensaje "Lorem ipsum dolor sit amet"}
(map (fn [[k v]] {k {:__value v}}))
(into {}))``````

3
Michael Stokley19:04:44

but i think `reduce` is the right tool

Joseph Rollins19:04:17

I knew there had to be a way to do this with into and transducers, but I'm still getting more comfortable with transducers

theequalizer7319:04:00

Very nice. I got it! Thank you all!

👍 3
pez19:04:07

@orlandomr27, since the output vector has as many items as the input vector, I think `map` is a good choice. So if you make a function `f` that can take one of those hashmaps and transform it into the new form, then `(map f input-vector)`.

pez19:04:17

I would define `f` something like so:

``````(defn f [x]
(let [new-x (-> x
(assoc :numero {:__value (:numero x)})
(assoc :mensaje {:__value (:mensaje x)})
(assoc :remitente {:__value "PLIM"}))]
{:clMensajes new-x}))``````

theequalizer7319:04:36

Awesome! just what I needed. Thank you @pez

theequalizer7319:04:29

So simple. I confess I tried this approach but I was missing the last exp.

pez19:04:07

You are welcome!

piyer22:04:33

I am trying to add logging to my project, I couldn't find any documentation on where to add these config files: https://github.com/clojure/tools.logging#log4j2 any pointers?

seancorfield22:04:48

@munichlinux “on your classpath” which generally means in the `resources` folder of your project if you have one (or else the `src` folder).

seancorfield22:04:28

If you’re going down the `log4j2` path — which is what we use at work — you’re also probably going to need bridge libraries to route all over logging through log4j2 and also the JVM option to tell `tools.logging` to use log4j2 in preference other logging libraries it finds on the classpath.

seancorfield22:04:58

This is the JVM option: `-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory`

piyer22:04:26

got it. What should I name this config file?

seancorfield22:04:10

Here are the bridge libraries (for you dependencies):

``````;; use log4j 2.x:
org.apache.logging.log4j/log4j-api {:mvn/version "2.13.3"}
;; bridge into log4j:
org.apache.logging.log4j/log4j-1.2-api {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-jcl {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-jul {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-slf4j-impl {:mvn/version "2.13.3"}``````
(that’s in `deps.edn` format but I expect you get the idea)

seancorfield22:04:54

If you follow the link from c.t.l to log4j2's docs, you’ll see you have a lot of options for how you actually do the configuration.

piyer22:04:46

got it. I thought, I can copy the config there and get it to work.

seancorfield22:04:06

@munichlinux Our default `log4j2.properties` file contains:

``````# QA/production normal mode, shows INFO and above, in plain text:
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{DEFAULT} %-5p [%c] - %X - %m%n

# We do not care about most of c3p0's INFO messages:
logger.c3p0.name = com.mchange.v2.c3p0
logger.c3p0.level = warn
logger.c3p0.appenderRef.stdout.ref = STDOUT

# We do not care about most of Redisson's INFO messages:
logger.redisson.name = org.redisson.connection
logger.redisson.level = warn
logger.redisson.appenderRef.stdout.ref = STDOUT``````
So we don’t get overwhelmed by c3p0 or redisson (although I think we’ve stopped using the latter and could remove that).

piyer22:04:46

Thanks a lot for the example.

seancorfield22:04:55

We have a default `log4j2.properties` file — we went with the properties style config rather than XML, JSON, or YAML.

seancorfield22:04:35

And then we have several alternative properties files that we select via environment variables or JVM options (properties) depending on what level/format of logging we want.

seancorfield22:04:46

(Java logging is insanely complicated, unfortunately)

piyer22:04:33

That make sense. so, I can copy and put that as `logback.edn` in my `resource`?

seancorfield22:04:42

And it certainly does not help that the Apache docs page shows XML primarily.

seancorfield22:04:57

What is `logback.edn`?

seancorfield22:04:03

It explains how it finds configuration options/files.

seancorfield22:04:23

As I said above: > We have a default `log4j2.properties` file — we went with the properties style config rather than XML, JSON, or YAML. That’s on our classpath.

piyer22:04:41

are ring logging compactable with log4j2? or should I use SLF4j?

seancorfield22:04:52

You can use log4j2 and have all logging routed to it — that’s what the bridging libraries above are for. Most of the logging systems have similar bridging libraries.

👍 3
seancorfield22:04:09

Not sure what you mean by “ring logging”.

seancorfield22:04:31

Lots of Java libraries choose different logging solutions. That’s why you need bridge libraries.

seancorfield22:04:15

If you want to use log4j2, Jetty will also use it — via the log4j2 bridge for slf4j (I listed the bridge libraries above).

seancorfield22:04:43

You want all four bridge libraries so that all the Java libraries your app ends up pulling it will all be routed to log4j2.

piyer22:04:57

Thank you. I will try that.

seancorfield22:04:34

That is how you control all the logging: so you have your configuration (for log4j2) and all the other logging libraries in your project route to log4j2 and obey that configuration.

seancorfield22:04:34

seancorfield22:04:13

Just don’t forget the JVM option `-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory` when you are running your app!

piyer22:04:30