clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
eskos 2021-05-24T01:41:38.299100Z

Not claiming this is any prettier, but it is different enough to warrant showing. Maybe use this as an excuse to read about a few useful functions in Clojure API? 🙂

(->> {:a [1 2 3] :b [4]}
     (mapcat (fn [[k v]]
       (map (partial vector k) v)))
     (map reverse)
     (reduce #(apply (partial assoc %1) %2) {}))

Ivan Koz 2021-05-24T09:15:54.303Z

@ben.sless nearly all clojure functions operating on sequences are lazy

Ben Sless 2021-05-24T09:17:41.303200Z

@nxtk There are plenty of opportunities to go through the transducing arity if all you're using is the core library

Ivan Koz 2021-05-24T09:18:46.303400Z

Can you show us non lazy solution?

Ben Sless 2021-05-24T09:19:19.303600Z

The solution I provided is non lazy

Ivan Koz 2021-05-24T09:19:48.303800Z

oh i see it now, thank you, i'll look closer

Ben Sless 2021-05-24T09:20:28.304100Z

🙂 How to spot it: mapcat doesn't take m as an argument

Ben Sless 2021-05-24T09:22:40.304300Z

Also, the inner map doesn't take vs as an argument, i.e. it returns a transducer, which is one of the two arguments to the eduction constructor

Ivan Koz 2021-05-24T09:23:25.304500Z

right, i understand transducers concept, just never seen them in that context of laziness, thank you

Ben Sless 2021-05-24T09:54:02.305Z

In which context do you usually see them, then?

Ivan Koz 2021-05-24T15:10:26.317300Z

composable, decoupling transformations

lassemaatta 2021-05-24T04:07:28.299200Z

I was just about to reference the old .kkrieger game as a nice example of what people can do with just 96 kilobytes, but then I noticed that the game jam already references it as an inspiration 😄

2021-05-24T05:01:38.301100Z

Is there any idiomatic way to group a map by its namespaced keywords? for instance, I’d like to divide {:user/id 1 :user/name "abc" :test/id 2 :test/name "def"} into {:user/id 1 :user/name "abc"} {:test/id 2 :test/name "def"}

seancorfield 2021-05-24T16:48:35.325200Z

I’d probably just use select-keys to pull out the specific fields I wanted, to make the selection explicit.

2021-05-25T05:02:51.372800Z

Thanks, that can also work.

2021-05-24T05:03:22.301400Z

I could use filter with (= (namespace key) “key_name”), but wonder if there is more succinct way of doing it.

seancorfield 2021-05-24T05:13:48.301700Z

dev=> (def m {:user/id 1 :user/name "abc" :test/id 2 :test/name "def"})
#'dev/m
dev=> (map #(into {} %) (vals (group-by (comp namespace key) m)))
(#:user{:id 1, :name "abc"} #:test{:id 2, :name "def"})
if you want the whole thing split by namespace in one go.

seancorfield 2021-05-24T05:14:08.301900Z

But I would ask “Why do you need/want this?”

👀 1
seancorfield 2021-05-24T05:14:58.302100Z

(i.e., what situation are you in that you’re getting a map with mixed namespace qualifiers where you need to treat those qualifiers as structural information rather than global identity?)

2021-05-24T05:24:56.302300Z

Thanks for answering! This happened when joining two tables, and using a portion of data from one table to make a token.

borkdude 2021-05-24T12:47:41.305600Z

Is this a bug?

user=> (intern *ns* (with-meta '*foo* {:dynamic true}))
#'user/*foo*
user=> (binding [*foo* 2])
Execution error (IllegalStateException) at user/eval233 (REPL:1).
Can't dynamically bind non-dynamic var: user/*foo*

p-himik 2021-05-24T13:11:44.305800Z

Can't answer the question but can explain why it works that way, if it's useful. The ^:dynamic metadata is only taken into account when the def form is parsed. It's not read from the var. Instead (.isDynamic v) is called.

1
p-himik 2021-05-24T13:12:28.306Z

So in the above case, (.isDynamic #'*foo*) will return false.

borkdude 2021-05-24T13:12:41.306200Z

right

p-himik 2021-05-24T13:13:34.306400Z

And there's still a way to make it work dynamically:

user=> (.setDynamic #'*foo*)
#'user/*foo*
user=> (binding [*foo* 2])
nil

borkdude 2021-05-24T13:15:03.306600Z

makes sense. no non-interop way of doing it I'm afraid?

p-himik 2021-05-24T13:21:14.306800Z

Couldn't find it.

2021-05-24T14:32:39.308100Z

Is there any minimal examples out there on SSR with Reagent?

NoahTheDuke 2021-05-24T14:44:18.308500Z

might wanna ask in #reagent if you don’t get any answers in here

max minoS 2021-05-24T14:58:19.312200Z

I am trying to use Boot in my Mac (Big Sur), but for some reason it isn't letting me due to this bug (using the Homebrew version): https://github.com/boot-clj/boot/issues/765 Then, I cloned the repo in GitHub, which apparently already has the fix included, and tried building it using make install, but for some reason it is still giving me the same error. When I navigated to the file with that error and removed the error check completely, it still gave me the commented out error; so I think I didn't build it correctly. Can someone help me build it so that it will not just use the version? I couldn't understand what they had in the CONTRIBUTIONS.md for this situation

Sam Ritchie 2021-05-24T15:04:01.312700Z

hey all - is there a most efficient way to get the greatest element out of a sorted map?

NoahTheDuke 2021-05-24T15:04:38.312800Z

if it’s sorted, last?

Sam Ritchie 2021-05-24T15:05:06.313Z

I was under the impression that that walks the entire sequence of pairs, so has O(n) performance

2021-05-24T15:05:11.313200Z

No, last is implemented on the sequence abstraction, which means it always iterates the full list.

Sam Ritchie 2021-05-24T15:05:32.313400Z

peek for sorted maps is the goal here

NoahTheDuke 2021-05-24T15:05:48.313600Z

oh my apologies, you said map

wotbrew 2021-05-24T15:06:10.313800Z

you can use rsubseq or subseq @sritchie09 if you are testing the key

Sam Ritchie 2021-05-24T15:06:12.314Z

“sorted map”, ie, sorted-map

👍 1
p-himik 2021-05-24T15:06:28.314200Z

How do you launch boot ? Not sure if the command exists on Mac, but does which boot output the right path to the new binary?

2021-05-24T15:07:30.314500Z

rseq returns a reversed sequence in constant time

2021-05-24T15:07:43.314700Z

so (comp first rseq) would get the last item in constant time.

👍 1
2021-05-24T15:07:53.314900Z

For any reversible data structure.

max minoS 2021-05-24T15:07:54.315100Z

I created a shell script that points it to java -jar /path/to/boot.jar

max minoS 2021-05-24T15:08:18.315300Z

actually, I will compile it again now and check

2021-05-24T15:09:01.315700Z

You can test for this with reversible?, but sorted maps qualify.

djpowell 2021-05-24T15:09:54.316900Z

Is Java 11 the recommended version for Clojure atm? Are there issues running on later JREs? (just want to pick the right jre so I don't cause myself trouble)

alexmiller 2021-05-24T15:10:35.317800Z

yes, and no.

2021-05-24T15:10:41.317900Z

I run my clojure code on jdk 15 and everything (at least that I use) works fine

alexmiller 2021-05-24T15:11:18.318700Z

officially, we test and recommend using Clojure on LTS releases, of which Java 11 is the latest

alexmiller 2021-05-24T15:11:34.319100Z

unofficially, we test and have no known issues with non-LTS releases

djpowell 2021-05-24T15:11:46.319500Z

thanks - i've been away for a while 🙂

alexmiller 2021-05-24T15:12:03.319800Z

Java 17 is the next LTS release, scheduled for this fall

2021-05-24T15:12:40.320200Z

I hope that we can get clojure support for project panama soon after it gets released

alexmiller 2021-05-24T15:13:33.320300Z

what support is needed?

2021-05-24T15:16:27.320500Z

I'm not sure yet, especially since as far as I know the api is far from stabilized. It might be that it just ends up being some stdlib stuff that clojure will support out the gate. My (very incomplete and possibly incorrect) understanding however is that we'll need some way to declare foreign functions, and that it would be out-of-band from normal execution.

alexmiller 2021-05-24T15:16:39.320700Z

seems like all the jeps for it have been released as of Java 16?

2021-05-24T15:16:48.320900Z

Oh, I guess I'm out of date then.

max minoS 2021-05-24T15:17:04.321100Z

which boot returns ~/.bin/boot, which is where I placed my shell script

2021-05-24T15:17:22.321300Z

I guess I need to go look into the jeps

alexmiller 2021-05-24T15:17:52.321500Z

I'm not tracking this at all and have no idea what the gaps are between Java and Clojure. if you're interested in it, it would be great to discover that and write it up on http://ask.clojure.org if there is some gap to close

max minoS 2021-05-24T15:18:13.321700Z

#!/bin/bash
export JAVA_HOME="${JAVA_HOME:-/opt/homebrew/opt/openjdk}"
declare -a "options=($BOOT_JVM_OPTIONS)"
exec "${JAVA_HOME}/bin/java" "${options[@]}" -Dboot.app.path="${HOME}/.bin/boot" -jar "${HOME}/Applications/boot/bin/boot.jar" "$@"
this is the shell script, which I also found was the shell script created by Homebrew, except the JAR file was compiled by myself

2021-05-24T15:19:41.321900Z

I'll start doing some research and see if there's anything that needs to be added.

p-himik 2021-05-24T15:20:44.322100Z

If you're absolutely sure that that jar at "${HOME}/Applications/boot/bin/boot.jar" is the one you compiled and that it doesn't have that error detection code, then it's very strange. Maybe removing ~/.bin/boot can help, no clue. There are also #boot-dev and #boot - maybe someone there knows.

dharrigan 2021-05-24T15:21:26.322500Z

I run Clojure with Java 16, no issues observed at all.

ghadi 2021-05-24T15:21:56.322800Z

there's no support necessary AFAICT

ghadi 2021-05-24T15:22:03.323Z

just a library you can use

max minoS 2021-05-24T15:22:09.323200Z

yes, I am very sure that that is where the boot.jar is generated, and the ~/.bin/boot was also created by me (it's a folder in my PATH); thanks, I will ask there

alexmiller 2021-05-24T15:22:52.323400Z

looks like there are Java 17-EA builds with everything at https://jdk.java.net/panama/

2021-05-24T15:24:14.323600Z

That's really cool if it's just a library.

Sam Ritchie 2021-05-24T15:55:42.324Z

excellent, thank you!

emccue 2021-05-24T16:40:57.324400Z

yeah - no support needed, but there might be reasons to want maybe support for deftype metadata to make a primitive class

emccue 2021-05-24T16:42:21.324600Z

so like

(deftype ^{:primitive true} Thing [a b])
would disallow ^:volatile and ^:unsynchronized-mutable on fields but generate a primitive class

emccue 2021-05-24T16:42:49.324800Z

the actual bytecode for calling a method on a primitive class should be the same as usual

emccue 2021-05-24T16:45:56.325Z

beyond that there might be things like type hints being able to distinguish between stuff like Instant.ref and Instant.val

emccue 2021-05-24T16:48:39.325400Z

wait i am thinking of valhalla, ignore me

emccue 2021-05-24T16:49:48.325600Z

https://github.com/clj-python/libpython-clj <- whatever this project ends up doing with regards to panama is likely to be the way to go

emccue 2021-05-24T16:52:22.325900Z

https://techascent.com/blog/next-gen-native.html

ghadi 2021-05-24T17:22:10.327600Z

keep in mind that the JVM doesn't generally break things intentionally, so anything a "dusty old jar" does is likely to remain working in the future

Max 2021-05-24T18:01:29.329100Z

Is there an existing fn/macro in the standard library for the following pattern? It’s kind of like update, but for vars not maps.

(if condition (some-fn x) x)
If not, what would you call it?

Michael Gardner 2021-05-24T18:02:27.329200Z

cond-&gt;

ghadi 2021-05-24T18:02:31.329400Z

(cond-&gt; x condition (expr-that-uses-x ...))

Max 2021-05-24T18:04:42.329600Z

I’ve used cond-&gt; when I have multiple expressions, but it feels weird to use it for a single expression?

Michael Gardner 2021-05-24T18:09:37.329800Z

why would it be weird?

ghadi 2021-05-24T18:09:51.330Z

it becomes a judgement call

vncz 2021-05-24T18:10:41.330500Z

I’ve used it for single expressions as well and to me it just makes sense

2021-05-24T18:11:59.330700Z

I've called this when-pred

(defn when-pred
  [test? f]
  (fn apply-when-matches
    [x]
    (if (test? x)
      (f x)
      x)))
but I really think this depends on the coding style you and your collaborators are comfortable with - I use this when my collaborators are as fond of higher order functions as I am

walterl 2021-05-24T18:12:13.330900Z

It definitely makes sense, and I've used it for single expressions too, but when I ask myself what reads easier, I revert back to if every time 😅

2021-05-24T18:13:58.331100Z

also - depending on context, this can easily become a multimethod

BuddhiLW 2021-05-24T20:12:40.335400Z

I'm using closh to make a script which converts a "pattern<number>.ext" => "pattern<(- number constant)>.ext". I run in the following problem:

$ (map #'first ["teste1.txt" "teste{2..3}.txt" "teste2.txt" "teste3.txt"])
(\t \t \t \t)
$ (map #'id-extension ["teste1.txt" "teste{2..3}.txt" "teste2.txt" "teste3.txt"])
Error printing return value (ClassCastException) at clojure.string/split (string.clj:219).
class java.lang.Character cannot be cast to class java.lang.CharSequence (java.lang.Character and java.lang.CharSequence are in module java.base of loader 'bootstrap')
$ ls |&gt; (first)
"teste1.txt"
$ ls |&gt; (first) |&gt; (id-extension)
"1.txt
That is, the function:
(defn id-extension [name]
  (-&gt;
   (map #(str/split % #"teste") name)
   (first)
   (second)))
Only works if I apply it to a single object. If I use map on it, it throws me this error. Does anyone know how do I fix this? OBS:
$ ls |&gt; (identity)
("teste1.txt" "teste{2..3}.txt" "teste2.txt" "teste3.txt")

2021-05-24T20:17:08.338400Z

You have too many map s in your code. The outer most map calls id-extension with each filename from your vector. Then, inside id-extension, you are calling map again, which means you’re taking each individual character in the file name, and trying to pass it to str/split. Get rid of the map inside id-extension and just call str/split directly.

BuddhiLW 2021-05-24T20:28:20.338600Z

Like this?

2021-05-24T20:32:08.338800Z

name is a built-in Clojure function, that may be giving you problems, try naming your argument filename or something.

BuddhiLW 2021-05-24T20:42:31.339Z

Yeah, I really don't get it.

$   (defn id-extension [filename]
#_=&gt;     (-&gt;
#_=&gt;      (str/split filename #"teste")
#_=&gt;      (first)
#_=&gt;      (second)))
#_=&gt; 
#'user/id-extension

$ ls |&gt; (first) |&gt; (map #(str/split % #"teste")) |&gt; (first) |&gt; (second)
"1.txt"

$ ls |&gt; (id-extension)
Execution error (ClassCastException) at user/eval6839$id-extension (REPL:0).
class clojure.lang.Cons cannot be cast to class java.lang.CharSequence (clojure.lang.Cons is in unnamed modu
le of loader 'app'; java.lang.CharSequence is in module java.base of loader 'bootstrap')

2021-05-24T20:46:10.339200Z

Hmm, what’s the code that’s calling id-extension now?

seancorfield 2021-05-24T20:46:32.339400Z

You might want to try working with these functions in a regular REPL first to make sure you understand how map works (and perhaps ask in #beginners where folks have opted-in to helping folks with stuff like this).

👍 1
☝️ 1
seancorfield 2021-05-24T20:52:47.339700Z

The thing to bear in mind about closh is that |&gt; always sends a sequence of lines, so ls |&gt; (first) |&gt; (map ..) sends a sequence containing only one element into the map function. That’s the difference from Clojure.

seancorfield 2021-05-24T20:53:37.339900Z

Your id-extension function expects a string but ls |&gt; (id-extension) sends it a sequence of strings.

seancorfield 2021-05-24T20:56:08.340100Z

$ ls |&gt; (identity)
("bin" "deps.edn" "scratch.clj" "script.clj" "src" "wheel")
$ ls |&gt; (first)
"bin"
$ ls |&gt; (first) |&gt; (identity)
["bin"]
ls |&gt; sends a sequence of strings into the (identity) call, and also into the (first) call — so the latter produces just a string — but ls |&gt; (first) |&gt; (identity) sends a sequence containing that string into the (identity) call.

BuddhiLW 2021-05-24T21:00:14.340700Z

Ok, I see. Considering that, It worked

(defn split-teste [filename]
  (-&gt;
    (str/split filename #"teste")
    (second)))

$  ls |&gt; (map split-teste)
("1.txt" "2.txt" "3.txt")

✅ 1
BuddhiLW 2021-05-24T21:00:36.341100Z

I will head to the #beginners . Thank you.

Daniel 2021-05-24T21:01:03.341500Z

Hi there, is there a way to create a repl from inside a spring boot application written in clojure?

BuddhiLW 2021-05-24T21:02:01.341600Z

Also, reducing the quantities of maps, just like @manutter51 said helped closing-in the solution

ghadi 2021-05-24T21:05:22.342600Z

easiest way is to launch a REPL using the "socket server" https://clojure.org/reference/repl_and_main#_launching_a_socket_server @beshatku

ghadi 2021-05-24T21:06:23.343700Z

(sometimes you hear people say "socket REPL", which is a socket server that runs a REPL, but the socket server can run anything)

Daniel 2021-05-24T21:06:53.344200Z

Alright thanks, going to give that a try

Daniel 2021-05-24T21:34:16.345200Z

I’ve tried to add that properties into application.properties used by Spring but the socket server doesn’t appear to have been launched. @ghadi

ghadi 2021-05-24T21:36:17.347400Z

the properties mechanism will only work if Clojure gets initialized. If you add a call to any method on clojure.java.api.Clojure it will do the trick

Daniel 2021-05-24T21:46:53.348200Z

@ghadi Well I did try to invoke Clojure from -main but the socket server doesn’t appear to have been launched:

(defn -main [&amp; [args]]
    (do (prn "Running with" args)
        (let [plus (Clojure/var "clojure.core" "+")]
          (prn (plus 4)))
        (SpringApplication/run krypto.core.Application (into-array [""]))))

ghadi 2021-05-24T21:50:12.348800Z

Please paste the system property you are using

Daniel 2021-05-24T21:50:41.349200Z

clojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"

ghadi 2021-05-24T21:52:06.350200Z

Are you launching spring from clojure? Or clojure from spring?

Daniel 2021-05-24T21:53:31.352Z

I’m launching clojure from spring. So this is how I launch it:

mvn spring-boot:run
Inside pom.xml are:
&lt;dependency&gt;
      &lt;groupId&gt;org.clojure&lt;/groupId&gt;
      &lt;artifactId&gt;clojure&lt;/artifactId&gt;
      &lt;version&gt;1.10.0&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter&lt;/artifactId&gt;
      &lt;version&gt;2.4.5&lt;/version&gt;
    &lt;/dependency&gt;
And
&lt;plugin&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.4.5&lt;/version&gt;
      &lt;/plugin&gt;

ghadi 2021-05-24T21:54:10.352900Z

So what’s that -main method above, experiment?

Daniel 2021-05-24T21:54:43.353400Z

It’s the entry point to the SpringApplication.

(:gen-class :name ^{org.springframework.boot.autoconfigure.SpringBootApplication true}
              foobar.core.Application))

ghadi 2021-05-24T21:57:51.355300Z

if you control the entrypoint to this application, you can just launch the repl explicitly

ghadi 2021-05-24T21:58:49.356300Z

and passing the arguments above as ordinary clojure data {:port 5555 :accept 'clojure.core.server/repl}

ghadi 2021-05-24T21:58:53.356500Z

note the quote on the symbol

ghadi 2021-05-24T22:00:01.357300Z

actually you'll have to pass :name as well

Daniel 2021-05-24T22:01:19.358900Z

Thanks @ghadi that worked!

ghadi 2021-05-24T22:01:21.359Z

the system properties-based invocation is a bit magical. It's applicable where 1) Clojure is getting loaded on the classpath 2) but you don't necessarily control the entrypoint

Daniel 2021-05-24T22:01:52.359600Z

I see, yeah, it didn’t work in this case I had to call start-server

ghadi 2021-05-24T22:02:51.360600Z

(note that with the system properties approach, you do not have to call start-server at all -- I suspect your problem was not having the system property present)

Daniel 2021-05-24T22:06:14.362700Z

Hmm, that’s what I suspected too, I did try to pass in the properties through the Spring app.properties file and tried to include that on the mvn invocation, ie:

mvn spring-boot:run -Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"
But these didn’’t work

ghadi 2021-05-24T22:06:58.363500Z

yeah I'm not a mvn-ologist but it's unclear to me if that -D applies to the mvn process, or the jvm that the mvn process launches

Daniel 2021-05-24T22:07:12.364100Z

Oh wait, I need to specify -Drun.jvmArguments= instead

1
ghadi 2021-05-24T22:07:15.364200Z

you can confirm what system properties exist on a running JVM by calling: jcmd &lt;the pid&gt; VM.system_properties | grep clojure