This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-26
Channels
- # asami (5)
- # babashka (9)
- # beginners (19)
- # calva (14)
- # cider (13)
- # clj-kondo (9)
- # cljfx (2)
- # clojure (51)
- # clojure-bay-area (1)
- # clojure-europe (26)
- # clojurescript (23)
- # code-reviews (7)
- # core-async (1)
- # datahike (4)
- # datalevin (3)
- # emacs (2)
- # kaocha (2)
- # malli (6)
- # nrepl (3)
- # polylith (3)
- # re-frame (15)
- # reveal (1)
- # shadow-cljs (13)
- # tools-deps (6)
I've been away from clojure for a while. Can someone remind my the clojure idiom for the following lispy idiom?
I.e., the outer mapcat
maps a binary function over two sequences qs
and transitions
, not concentrically but in parallel, and the inner map
iterates a unary function over a list of pairs, while binding label
and y
for each pair.
(mapcat (fn [x pairs]
(map (fn [[label y]]
[x label (qs y)])
pairs))
qs transitions)
qs
in a vector, as I recall that is map-like
how do you normally access vectors?
nth
usually. But using vectors as callables should be perfectly fine if you know for sure that it's a vector and that the arguments are indices that exist within the vector.
You phrased your question as if there is an idiom for such a process. Are you sure there is one?
I'm not exactly an expert here, but your code looks as concise as I would expect, given parts of clojure.core
I remember.
I was under the impression that people avoid mapcat
. and tend to use for
comprensions. I'm happy with mapcat
myself.
(An essay related to @U2FRKM4TW's note about concat: https://stuartsierra.com/2015/04/26/clojure-donts-concat)
Question about group-by
If I want to partition a given sequence into equivalence classes according to a probe function f
, I can use (group-by f my-seq)
. E.g., (group-by first my-seq)
will transform
[[1 2 3] [10 20 30] [100 200 300] [1 5 6 7]]
-> {1 -> [[1 2 3] [1 5 6 7]], 10 -> [[10 20 30]], 100 -> [[100 200 300]]}
, In Scala I have a useful varient of this which does not collect the elements such as [1 2 3]
, [10 20 30]
, but rather applies a given function and collects those values.
e.g., (group-map first my-seq rest)
will give me a map from the first element of each sequence to list sequence of rest
s giving me the equivalent of {1 -> [[2 3] [5 6 7]], 10 -> [[20 30]], 100 -> [[200 300]]}
Do we have such a cousin of group-by
in scala? Of course I can create one in 2 lines, but the 2-line version creates lots of intermediate sequences.
(defn group-map [f seq g] ;; untested
(into {} (for [[k vs] (group-by f seq)]
[k (map g vs)])))
You can write such a function in 3 lines without any intermediate sequences:
(defn group-map [f seq g]
(reduce (fn [acc v]
(update acc (f v) (fnil conj []) (g v)))
{} seq))
And you can add transient
and persistent!
calls for that {}
if needed.I might be wrong but given my recent exposure to xforms
it feels like that library might have something for that.
(require '[net.cgrand.xforms :as x])
(into {} (x/by-key first next (x/into [])) [[1 2 3] [4 5 6] [1 9 0]]) ;=> {1 [(2 3) (9 0)], 4 [(5 6)]}
something like that?Having these two ways of destructuring:
(fn [{:keys [name surname age]}]
(str name ", " surname ", " age))
(fn [{:keys [:name :surname :age]}]
(str name ", " surname ", " age))
I used to use the first syntax, just recently noticed the other.
What is the difference?
When each of these should be used?
What is your personal/team preference and why?You should use the first one
Accepting keywords in the :keys was a workaround specifically to allow auto resolved keyword support, but that’s now better supported on :keys itself
Ideally you are always specifying the local symbols that are being bound
So they were added to support doing something like {:keys [::a]}
Or {:keys [::an-alias/a]}
But you can now better do {::keys [a]}
or {::an-alias/keys [a]}
ok, thanks a lot for clarification @U064X3EF3 🙇
I'm surprised to learn that (mapcat f set-of-sequences)
returns a list rather than a set even in the case that f
returns a set. I filled up memory with a huge list of repeated elements.
E.g., (mapcat set #{[1 2 3] [2 3 4] [3 4 5]})
this returns (4 3 5 4 3 2 1 3 2)
not #{1 2 3 4 5}
this is weirdly inkeeping with the documentation as (concat (set [1 2 3]) (set [2 3 4]))
returns (1 2 3 2 3 4)
not #{1 2 3 4}
. that's shocking though
shouldn't the concatenation of two sets be the union? not the concatenation of the sets each converted to lists?
Depends on the abstraction.
Union of the sets is, well, a union.
Concatenation in Clojure operates at the seq
level - from its POV, sets are just collections, it doesn't care about the intrinsics.
I was thinking based on contains?
checks requiring realization. But i guess there could be partially realized sets. Sounds like a dangerous data structure that is not great for general purposes though
there are surely some useful datastructures like this but calling them a generic set would be misleading
good point. but still this was a surprising bug in my program. I thought it was an infinite loop. no it was just building a huge seqence of the same thing over and over. I was thinking the semantics were set-like, not sequence like. lesson learned!
yeah, the mental model I believe we are meant to have is "sequence operations take in 'seq-able' things and output a sequence."
Yes, once I understood the problem it is easy to fix by calling reduce
using union
. just surprising. I've been using Scala for a while, and the equivalent of mapcat
in Scala preserves the monadic structure. At least from the point of view of the beginner.
Are reader tags tagging meta data or the form that the meta data is attached to?
1. |#a ^:a| a b
2. |#a ^:a a| b
The form. The metadata by itself is not a valid form. And it's easy enough to test:
(defn test-reader [_ form]
{:meta (meta form)
:form form})
(set! *default-data-reader-fn* test-reader)
#a ^:x []
=> {:meta {:x true}, :form []}
The metadata was set on the results of the reader tag function. Try wrapping the whole statement in (meta ...)
.
I have successfully generated a Java class from clojure code using :gen-class
I'm able to export it as a JAR, and use that class from another Java Project
now I need to write clojure tests for that generated java class
(not the clojure namespace that contains the code the generate the class)
in my test namespace I naively (:import
ed my class (instead of the clj namespace), but its complaining that the class does not exists. It makes sense after all someone needs to compile that clj file into a class and add into the class path
whats the best way of achieving this?