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

since I sent you here and and you actually followed that, I'll try to help you, though it'll not be to your satisfaction probably I have no idea about how you would do that and I'm not about to figure it out. But if I were you and would want to do that, I would: Follow the getting started tutorial on http://heroku.com for clojure and analyze exactly how it works. And then read probably all of the Heroku documentation until I understand exactly how Heroku works. I assume you did neither of that. If you just want to do things quick and have results without actually understanding the stuff you want to do, you're probably out of luck. You will actually have to invest the time to read and really dive into the subject, which will probably take hours, or even days/weeks/months if you're relatively new to programming. You asked "how to do X?". The answer above was "well, you got to learn how X works". And you'll likely not get any other answer than that. BUT. I'll let you into a little secret and give you a one-time offer. You seem very new to all this. How about instead of asking "how to do X?" you ask "hey, I want to reach Y goal. I wanted to reach that by doing X. I tried to do X but I had [some trouble that you explain]. Is that the right way to go about it? How can I solve [some trouble] or is there something else I should do?" In other words, instead of asking how to do a specific thing, you tell us your goals and what you tried and why it didn't work, which you currently did not do at all. When you do that, you may actually get a good answer, and it may be something much simpler than what you originally tried. And my offer is, if you do that, I'll do my best to answer that new question for you.

🙌 6
raspasov12:04:30

All of the above sounds about right.

Edward Ciafardini14:04:43

this is a really good answer

introom01: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

since I sent you here and and you actually followed that, I'll try to help you, though it'll not be to your satisfaction probably I have no idea about how you would do that and I'm not about to figure it out. But if I were you and would want to do that, I would: Follow the getting started tutorial on http://heroku.com for clojure and analyze exactly how it works. And then read probably all of the Heroku documentation until I understand exactly how Heroku works. I assume you did neither of that. If you just want to do things quick and have results without actually understanding the stuff you want to do, you're probably out of luck. You will actually have to invest the time to read and really dive into the subject, which will probably take hours, or even days/weeks/months if you're relatively new to programming. You asked "how to do X?". The answer above was "well, you got to learn how X works". And you'll likely not get any other answer than that. BUT. I'll let you into a little secret and give you a one-time offer. You seem very new to all this. How about instead of asking "how to do X?" you ask "hey, I want to reach Y goal. I wanted to reach that by doing X. I tried to do X but I had [some trouble that you explain]. Is that the right way to go about it? How can I solve [some trouble] or is there something else I should do?" In other words, instead of asking how to do a specific thing, you tell us your goals and what you tried and why it didn't work, which you currently did not do at all. When you do that, you may actually get a good answer, and it may be something much simpler than what you originally tried. And my offer is, if you do that, I'll do my best to answer that new question for you.

🙌 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: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 [email protected]))`?

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 [email protected](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

omendozar18: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

omendozar19: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

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

omendozar19:04:36

Awesome! just what I needed. Thank you @pez

omendozar19: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

This article might help you https://lambdaisland.com/blog/2020-06-12-logging-in-clojure-making-sense-of-the-mess (although it picks sl4j but I think log4j2 is a better choice).

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

Thank you, that is helpful.

seancorfield22:04:13

And don’t use Timbre or slf4j-timbre. Stick with standard Java logging or you’ll just make life even more confusing.

piyer22:04:59

That is good to know.