This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-24
Channels
- # announcements (1)
- # babashka (86)
- # beginners (75)
- # boot-dev (1)
- # cljdoc (18)
- # cljs-dev (1)
- # cljsrn (67)
- # clojure (127)
- # clojure-australia (1)
- # clojure-dev (2)
- # clojure-europe (9)
- # clojure-nl (2)
- # clojure-serbia (2)
- # clojure-spec (11)
- # clojure-uk (14)
- # clojurescript (17)
- # code-reviews (4)
- # conjure (37)
- # core-async (11)
- # datomic (21)
- # emacs (1)
- # helix (36)
- # jobs (6)
- # malli (1)
- # meander (20)
- # re-frame (13)
- # reagent (49)
- # remote-jobs (11)
- # rum (1)
- # sci (1)
- # shadow-cljs (29)
- # sql (17)
- # vim (2)
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) {}))
mapcat
is a good start, but why go through laziness at all?
(into {} (mapcat (fn [[k vs]] (->Eduction (map (fn [v] [v k])) vs))) m)
@UK0810AQ2 nearly all clojure functions operating on sequences are lazy
@UH16CGZC2 There are plenty of opportunities to go through the transducing arity if all you're using is the core library
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
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 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.(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.
Iâd probably just use select-keys
to pull out the specific fields I wanted, to make the selection explicit.
mapcat
is a good start, but why go through laziness at all?
(into {} (mapcat (fn [[k vs]] (->Eduction (map (fn [v] [v k])) vs))) m)
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.
And there's still a way to make it work dynamically:
user=> (.setDynamic #'*foo*)
#'user/*foo*
user=> (binding [*foo* 2])
nil
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
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?
#!/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 myselfIf 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.
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
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
@U017QJZ9M7W if you are testing the key
rseq returns a reversed sequence in constant time
For any reversible data structure.
You can test for this with reversible?
, but sorted maps qualify.
excellent, thank you!
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
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.
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
I'll start doing some research and see if there's anything that needs to be added.
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.
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
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->
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?
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.
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")
Also, reducing the quantities of maps, just like @U06CM8C3V said helped closing-in the solution
Hi there, is there a way to create a repl from inside a spring boot application written in clojure?
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)
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 [""]))))
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>
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}
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
(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 work