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) {}))
@ben.sless nearly all clojure functions operating on sequences are lazy
@nxtk There are plenty of opportunities to go through the transducing arity if all you're using is the core library
Can you show us non lazy solution?
The solution I provided is non lazy
oh i see it now, thank you, i'll look closer
🙂
How to spot it:
mapcat
doesn't take m
as an argument
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
right, i understand transducers concept, just never seen them in that context of laziness, thank you
In which context do you usually see them, then?
composable, decoupling transformations
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 😄
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"}
I’d probably just use select-keys
to pull out the specific fields I wanted, to make the selection explicit.
Thanks, that can also work.
I could use filter with (= (namespace key) “key_name”), but wonder if there is more succinct way of doing it.
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.But I would ask “Why do you need/want this?”
(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?)
Thanks for answering! This happened when joining two tables, and using a portion of data from one table to make a token.
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*
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.
So in the above case, (.isDynamic #'*foo*)
will return false.
right
And there's still a way to make it work dynamically:
user=> (.setDynamic #'*foo*)
#'user/*foo*
user=> (binding [*foo* 2])
nil
makes sense. no non-interop way of doing it I'm afraid?
Couldn't find it.
Is there any minimal examples out there on SSR with Reagent?
might wanna ask in #reagent if you don’t get any answers in here
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
hey all - is there a most efficient way to get the greatest element out of a sorted map?
if it’s sorted, last
?
I was under the impression that that walks the entire sequence of pairs, so has O(n) performance
No, last is implemented on the sequence abstraction, which means it always iterates the full list.
peek
for sorted maps is the goal here
oh my apologies, you said map
you can use rsubseq
or subseq
@sritchie09 if you are testing the key
“sorted map”, ie, sorted-map
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?
rseq returns a reversed sequence in constant time
so (comp first rseq)
would get the last item in constant time.
For any reversible data structure.
I created a shell script that points it to java -jar /path/to/boot.jar
actually, I will compile it again now and check
You can test for this with reversible?
, but sorted maps qualify.
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)
yes, and no.
I run my clojure code on jdk 15 and everything (at least that I use) works fine
officially, we test and recommend using Clojure on LTS releases, of which Java 11 is the latest
unofficially, we test and have no known issues with non-LTS releases
thanks - i've been away for a while 🙂
Java 17 is the next LTS release, scheduled for this fall
I hope that we can get clojure support for project panama soon after it gets released
what support is needed?
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.
seems like all the jeps for it have been released as of Java 16?
Oh, I guess I'm out of date then.
which boot
returns ~/.bin/boot
, which is where I placed my shell script
I guess I need to go look into the jeps
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
#!/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 myselfI'll start doing some research and see if there's anything that needs to be added.
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.
I run Clojure with Java 16, no issues observed at all.
there's no support necessary AFAICT
just a library you can use
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
looks like there are Java 17-EA builds with everything at https://jdk.java.net/panama/
That's really cool if it's just a library.
excellent, thank you!
yeah - no support needed, but there might be reasons to want maybe support for deftype metadata to make a primitive class
so like
(deftype ^{:primitive true} Thing [a b])
would disallow ^:volatile and ^:unsynchronized-mutable on fields but generate a primitive classthe actual bytecode for calling a method on a primitive class should be the same as usual
beyond that there might be things like type hints being able to distinguish between stuff like Instant.ref
and Instant.val
wait i am thinking of valhalla, ignore me
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
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
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?cond->
(cond-> x condition (expr-that-uses-x ...))
I’ve used cond->
when I have multiple expressions, but it feels weird to use it for a single expression?
why would it be weird?
it becomes a judgement call
I’ve used it for single expressions as well and to me it just makes sense
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 amIt 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 😅
also - depending on context, this can easily become a multimethod
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 |> (first)
"teste1.txt"
$ ls |> (first) |> (id-extension)
"1.txt
That is, the function:
(defn id-extension [name]
(->
(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 |> (identity)
("teste1.txt" "teste{2..3}.txt" "teste2.txt" "teste3.txt")
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.
Like this?
name
is a built-in Clojure function, that may be giving you problems, try naming your argument filename
or something.
Yeah, I really don't get it.
$ (defn id-extension [filename]
#_=> (->
#_=> (str/split filename #"teste")
#_=> (first)
#_=> (second)))
#_=>
#'user/id-extension
$ ls |> (first) |> (map #(str/split % #"teste")) |> (first) |> (second)
"1.txt"
$ ls |> (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')
Hmm, what’s the code that’s calling id-extension
now?
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).
The thing to bear in mind about closh
is that |>
always sends a sequence of lines, so ls |> (first) |> (map ..)
sends a sequence containing only one element into the map
function. That’s the difference from Clojure.
Your id-extension
function expects a string but ls |> (id-extension)
sends it a sequence of strings.
$ ls |> (identity)
("bin" "deps.edn" "scratch.clj" "script.clj" "src" "wheel")
$ ls |> (first)
"bin"
$ ls |> (first) |> (identity)
["bin"]
ls |>
sends a sequence of strings into the (identity)
call, and also into the (first)
call — so the latter produces just a string — but ls |> (first) |> (identity)
sends a sequence containing that string into the (identity)
call.Ok, I see. Considering that, It worked
(defn split-teste [filename]
(->
(str/split filename #"teste")
(second)))
$ ls |> (map split-teste)
("1.txt" "2.txt" "3.txt")
I will head to the #beginners . Thank you.
Hi there, is there a way to create a repl from inside a spring boot application written in clojure?
Also, reducing the quantities of maps, just like @manutter51 said helped closing-in the solution
easiest way is to launch a REPL using the "socket server" https://clojure.org/reference/repl_and_main#_launching_a_socket_server @beshatku
(sometimes you hear people say "socket REPL", which is a socket server that runs a REPL, but the socket server can run anything)
Alright thanks, going to give that a try
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
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
@ghadi Well I did try to invoke Clojure from -main
but the socket server doesn’t appear to have been launched:
(defn -main [& [args]]
(do (prn "Running with" args)
(let [plus (Clojure/var "clojure.core" "+")]
(prn (plus 4)))
(SpringApplication/run krypto.core.Application (into-array [""]))))
Please paste the system property you are using
clojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"
Are you launching spring from clojure? Or clojure from spring?
I’m launching clojure from spring. So this is how I launch it:
mvn spring-boot:run
Inside pom.xml are:
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.5</version>
</dependency>
And
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
So what’s that -main method above, experiment?
It’s the entry point to the SpringApplication.
(:gen-class :name ^{org.springframework.boot.autoconfigure.SpringBootApplication true}
foobar.core.Application))
if you control the entrypoint to this application, you can just launch the repl explicitly
by calling this https://clojure.github.io/clojure/clojure.core-api.html#clojure.core.server/start-server
and passing the arguments above as ordinary clojure data
{:port 5555 :accept 'clojure.core.server/repl}
note the quote on the symbol
actually you'll have to pass :name as well
Thanks @ghadi that worked!
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
I see, yeah, it didn’t work in this case I had to call start-server
(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)
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 workyeah 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
Oh wait, I need to specify -Drun.jvmArguments=
instead
you can confirm what system properties exist on a running JVM by calling:
jcmd <the pid> VM.system_properties | grep clojure