This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-02
Channels
- # adventofcode (153)
- # announcements (29)
- # architecture (6)
- # babashka (5)
- # beginners (197)
- # calva (71)
- # clj-kondo (27)
- # cljfx (4)
- # cljs-dev (33)
- # cljsrn (1)
- # clojure (52)
- # clojure-australia (5)
- # clojure-boston (1)
- # clojure-europe (38)
- # clojure-france (1)
- # clojure-hungary (5)
- # clojure-italy (1)
- # clojure-nl (19)
- # clojure-uk (5)
- # clojurescript (12)
- # conjure (4)
- # core-async (3)
- # cursive (22)
- # datalog (70)
- # datomic (32)
- # deps-new (8)
- # emacs (79)
- # events (2)
- # fulcro (15)
- # graalvm (15)
- # leiningen (2)
- # lsp (5)
- # minecraft (1)
- # nbb (1)
- # off-topic (37)
- # polylith (11)
- # re-frame (9)
- # reagent (1)
- # reitit (3)
- # releases (1)
- # reveal (2)
- # shadow-cljs (42)
- # spacemacs (1)
- # tools-build (4)
- # tools-deps (55)
- # vim (11)
- # xtdb (6)
I saw a reference in a thread recently about the Clojure style guide, and I saw this section: “https://guide.clojure.style/#pre-post-conditions” With the popularity of Spec, do people use these function conditionals anymore?
i would also question the popularity of spec - from where i’m sitting it doesn’t seem like usage is really widespread. i should find stats to confirm or refute that if they exist
I use pre (and sometimes post) conditions with some regularity. Some uses reach production, but often I use them during development to run expensive checks that I wouldn't want in production just to help failures happen closer to the root cause.
Interesting. Maybe I’ve watched too many Stuart Halloway YouTube videos. 😀 I’m just an amateur Clojurian, so it’s interesting to hear what the community actually uses. Out of curiosity, why don’t you use Spec?
We've been very heavy users of Spec ever since it appeared (in the prerelease cycle for Clojure 1.9 -- May 2016).
I don't really understand why some folks are resistant to it -- it's been incredibly useful for us.
As for :pre
/`:post`, we hardly ever use that in our code, so I agree with @U3JH98J4R about the popularity of those -- I very rarely see them in library code. Part of the issue is that they are "just" assertions so you get a runtime error rather than an exception.
The question is: what do you need to do if your function is passed an illegal argument? Do you want to return useful information or throw an exception (that the caller might be able to do something with)? Or do you want it to "fail fast" (and maybe terminate the program)?
Assertions -- including :pre
/`:post` -- are the latter.
I wrote about our use of Spec in mid-2019 https://corfield.org/blog/2019/09/13/using-spec/ -- TL;DR: we use it in production for a lot of in-function data validation but we also use it a lot in dev/test.
Deriving code from specs
In this case we write specs for data structures, such as rows in database tables, and then we generate named CRUD operations and supporting functionality from the specs themselves -- using macros that take specs as input with some control parameters and expand into a number of defn and other forms. The important aspect of this is that the spec is the "system of record" for the data structure: it can be used for validation, test data generation, and as the source for the keys and "types" that shape the functions needed to operate on them.
What are these specs like?Not sure what you're asking there?
I mean, they're Specs of hash maps, because that's what DB records are...
(internal screaming maximum volume)
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,1]
Message: JAXP00010001: The parser has encountered more than "64000" entity expansions in this document; this is the limit imposed by the JDK.
Apparently I can manually do java -Djdk.xml.entityExpansionLimit=0
but how can I also invoke clojure after setting that by the cmdline?
clojure -J-Djdk...
thank you!!!
@seancorfield so that gets me closer... but now I get Could not locate clojure/data/xml__init.class
Gotcha, something like this specifying the dependencies was necessary:
clojure -Sdeps "{:deps {org.clojure/data.xml {:mvn/version \"0.0.8\"}}}" -J-Djdk.xml.entityExpansionLimit=8256000 file.clj
Now I just have to make the code do the right thing 😅
You're on macOS/Linux? You can do
clojure -Sdeps '{:deps {org.clojure/data.xml {:mvn/version "0.0.8"}}}' -J-Djdk.xml.entityExpansionLimit=8256000 file.clj
I find that easier than wrestling with escaped quotes. I also tend to be very lazy when doing one-offs from the command-line and use "RELEASE"
instead of specific version if I don't care and just want a recent version.So if I invoke (prn (parse input))
I get a lot of terminal output for XML parsing
But when I try to write to a file with (spit file (parse input))
I get a file with the text clojure.data.xml.Element@87e76940
any pointers for what i'm missing?
(split file (pr-str (parse input)))
I think spit
assumes you've given it a string and doesn't try to convert it to one. That clojure.data.xml.Element
object has a .toString()
method I expect but prn
and pr-str
will try to convert arguments to strings.
why is
(seq x)
preferrable to
(not (empty? x))
at least according to the linter I have running?@fappy because empty?
is defined as (not (seq coll))
so (not (empty? x))
is (not (not (seq x)))
seq
is idiomatic in Clojure -- because of nil-punning -- so it's something you'll get used to.
Also, if you find yourself wanting (if (not (empty? x)) y z)
you can always write (if (empty? x) z y)
or, of course, (if (seq x) y z)
which is more idiomatic 🙂
Is there a way to use pre/post conditions in protocol methods?
The following code throws Unable to resolve symbol: % in this context
:
(defprotocol Test
(testing [_]))
(defrecord Tester [kw]
Test
(testing [_]
{:post [(string? %)]}
(str kw)))
It throws that error because '%' is a valid character only when inside an anonymous function starting with '#('
Or this for sth not quite so useless:
(defn test [a b]
{:post [(< (count %) 5)]}
(str a b))
(test "a" "c")
(test "adsdfsfd" "d")
And is there a particular reason why (keyword "a" "b c d")
returns :a/b
but {:a (keyword "a" "b c d")}
returns {:a :a/b, c d}
in cljs?
Edit:
Also (count {:a (keyword "a" "b c d")})
returns 1
but (count {:a :a/b 'c 'd})
returns 2
(maybe because the symbols in the first sexp don't resolve to anything?)
I am started with my first clojurescript project ans I am getting below error? can anyone help me please
What does your namespace declaration look in? At the top of the file it can't compile, will look like
(ns foo.bar
)
(ns raw-dom.core)
(def cnt-holder (.getElementById js/document "clicks"))
(def reset-btn (.getElementById js/document "reset-btn"))
(def cnt (atom 0))
(defn inc-clicks! []
(set! (.-innerHTML cnt-holder) (swap! cnt inc)))
(defn reset-clicks! []
(set! (.-innerHTML cnt-holder) (reset! cnt -1)))
(set! (.-onclick js/document) inc-clicks!)
(set! (.-onclick reset-btn) reset-clicks!)
The error looks to be in base64_vlq.clj, which won't be one of your files Have you seen this? https://github.com/nrepl/piggieback/issues/103
btw, there os nothing to load namespace for js here ? (.getElementById js/document "reset-btn") , doe it load by default ?
Hi. I'm trying to learn clojure by doing the advent of code lessons and I'm a bit stuck on syntax. `(->> (slurp "../day1/data1.txt") (clojure.string/split-lines) (map read-string) (partition 3 1) (map (reduce +)) ;; can't get this line to work (partition 2 1) (filter (fn [x] (< (first x) (second x)))) (count))` The code reads a file, converts it into a list of numbers, groups it into a list of lists and then I'm stuck trying to sum the inner lists with a wrong number of args exception. Could anyone help?
map takes a function, so you need to either use
(map (fn [x] ... ))
Or the shorthand version
(map #(...))
Just doing
(map (reduce +))
It will treat (reduce +)
just as an argument and try to evaluate it, hence an arrity error.Thanks a lot that was it
@seancorfield Very useful https://clojurians.slack.com/archives/C053AK3F9/p1638417446148700?thread_ts=1638414884.145500&cid=C053AK3F9 about "RELEASE"
as :mvn/version
. Is it a special deps value, a Maven shortcut, or a common convention for Clojure/Java libs?
It's a special virtual version understood by Maven but there are several caveats
First, it's only as good as the Maven repository metadata. With Maven central and Clojars those are updated by batch processes so lag slightly but are generally reliable. But s3 repos typically do not have this metadata and will tell you wrong answers
Second, this will violate some assumptions of the Clojure CLI classpath cache, namely that if the deps.edn doesn't change, the classpath doesn't change. So you need to -Sforce to notice new things. But for a tool install or a one off, this probably doesn't matter
Great notes, thanks @alexmiller
I see it's also https://cwiki.apache.org/confluence/display/MAVEN/Maven+3.x+Compatibility+Notes#Maven3.xCompatibilityNotes-PluginMetaversionResolution in Maven 3
Should still work in this context (you're using Maven 3 libs here)
(defn fo [a & {:as opts}]
[a opts])
;; What is the best way prior to clojure 1.11-alpha something
;; to pass opts?
;; I made use of this: in my code base a lot
(fo "a" {:b :c})
;; and now I want to downgrade to clojure 1.10
Why did transducers get implemented as single multi-arity functions, when those arities are each doing a fundamentally different thing? My first thought in that context would have been to use a protocol, but I'm guessing there's a good reason not to do it that way that I'm not seeing.
semantically, they are "like the seq version, but without the seq"
oh, you're asking about the impl spi side
it could have been a protocol, but that's a set of functions. as a single function, it's much easier to pass around the package.
I guess it would have been very OO – the transducer itself would wind up not representing any data, and would be a protocol function argument that does essentially nothing but determine the dispatch. I'd just never seen multiple arities used before to represent totally distinct operations. It "feels wrong", but that might be a malformed intuition on my part (and I'm assuming that it probably is, since y'all have much more experience with this stuff than I do).
Maybe my hesitation is that it seems strictly coincidental that the three operations take different numbers of arguments. I don't think I would have ever thought to rely on arity when, in principle (even if it's strictly hypothetical) two of the operations could have taken the same number of arguments
we did Java and JS impls too, in case you're curious https://github.com/cognitect-labs/transducers-java/tree/master/src/main/java/com/cognitect/transducers
I happened to read some papers on streams a few days ago and it seemed to me that transducers and operators fusion map almost 1-1, am I correct in that observation?
they have similar goals
More than the goals, I even went and read the implementations of the Rx streams operator factories (🤢 ), when you cut down all the java hand waving, it's the same
and ruby, and python. forgot about all those
Love - being non-sarcastic - how, for Python, the last commit was 7 years ago, there are 200 stars on the repo and just one issue opened. Meaning, well, it just works.
Hello. I wrote a function that takes a vector of dimensions and returns a corresponding matrix (a nested vector) with random elements (0 or 1). Although my solution works, I'm really interested in alternative ones, which may be more idiomatic. My code:
(defn random-grid
[[d & ds]]
(vec
(repeatedly
d
(if (seq ds)
#(random-grid ds)
#(rand-int 2)))))
I feel like there's something that can be done using partition
, but not sure how to do this for nested vectors.
Maybe using postwalk
?
(require '[clojure.walk :as walk])
(walk/postwalk
(fn [x]
(if (coll? x)
x
(vec (repeatedly x #(rand-int 2)))))
[2 [1 [3]]
2 [1 [4]]])
;;
;; [[1 1] [[1] [[1 1 0]]]
;; [0 1] [[0] [[1 1 0 0]]]]
Hmm, I think I wasn't clear enough about what I'm trying to achieve. The dimensions is not a nested vector. If it's [3 4] than I would like to get a 3x4 matrix, e.g.: [[0 1 1 1] [1 0 1 1] [0 0 0 0]]
(let [dims [2 3 4]]
(first
(reduce (fn [m d] (partition d m))
(repeatedly #(rand-int 2))
dims)))
;; =>
(((0 0) (1 0) (0 1))
((0 0) (1 1) (0 1))
((0 0) (0 0) (1 0))
((1 0) (1 1) (1 1)))
@U1Z392WMQ Yes, this works, but the result is a sequence, of sequences, not a nested vector.
I got it, but the solution now looks more complex than my initial one. Thanks for an alternative one though.
you could generate a random binary number with the right number of bits , then partition. takes infinity out of it, so vectors are fine.
Got it. But somehow I feel like there should be a more straightforward way... Are nested vectors even idiomatic in clojure? My goal is to have something that I could index like (grid [0 1 3]) or (get-in grid [3 5 2]). Should I use a map, maybe?
you can just treat the bit array as a flat array and index multidimensionally with your dims
No complex math, but I'll look into core.matrix to see if it fits my use case. Thanks a lot for your replies.
core.matrix.random
has what you need.
user=> (sample-rand-int [3 3 3] 2)
[[[1 0 1] [0 0 0] [0 0 1]] [[0 1 0] [1 1 0] [0 1 1]] [[0 0 0] [0 1 0] [1 0 1]]]
this is somewhere between a clojure and java question, so my apologies if this is the wrong channel. I’m trying to move off clj-time
to cljc.java-time
, and I’m not sure if I should be using Instant or LocalDateTime as my base unit. I’m not doing anything super fancy: i’m marking chat messages with timestamps, I’m querying mongodb with dates 3 months ago, etc.
I should say that I read this excellent SO answer (https://stackoverflow.com/questions/32437550/whats-the-difference-between-instant-and-localdatetime) about the difference between the various date types, I’m just unsure of exactly when is best to use them.
Instants are computer time (secs since the epoch), LocalDateTime is human time (Y/M/D stuff). So, different semantic points of view (latter maps to former based on time zones, laws, leap seconds etc).
I think I'd say people want people time on their messages (but in storage you might want instants)
> Where possible, applications should use LocalDate, LocalTime and LocalDateTime to better model the domain. For example, a birthday should be stored in a code LocalDate. Bear in mind that any use of a time-zone, such as ‘Europe/Paris’, adds considerable complexity to a calculation. Many applications can be written only using LocalDate, LocalTime and Instant, with the time-zone added at the user interface (UI) layer. • https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
(i’m not adding my own advice here but just directing to the quite extensive documentation they have for the package)
is there any way to generate the weekly dates from 2017-2021. For example today is thursday how to generate dates of Thursdays from 2017-2021 ?
(import java.time.LocalDate)
(->> (LocalDate/parse "2017-01-05")
(iterate #(.plusDays % 7))
(take-while #(> 2022 (.getYear %))))
(import java.time.LocalDate)
(import java.time.DayOfWeek)
(let [lo (LocalDate/of 2017 1 1)
hi (LocalDate/of 2022 1 1)]
(->> (iterate #(.plusDays ^LocalDate % 1) lo)
(take-while #(.isBefore ^LocalDate % hi))
(filter (comp #{DayOfWeek/THURSDAY} #(.getDayOfWeek ^LocalDate %)))))
I have a general question about clojure and navigating the clojure environment. Google has generally returned github results for clojure package searches. Some of these repo's haven't had a commit for 4-7 years. So my question is two fold. How stable/reliable are packages like these (this may be a how long is a piece of string question...though just building intuition here)? Is there a general index for up-to-date packages?
The language is very stable so many of these will be great. Same with Java packages that haven't seen updates in a while
If it does what you need, go ahead!
Awesome! Coming from R/Python where a lack of commits can be a red-flag for some packages, this is a great comfort. Appreciate the response.
Coming from Python, I was also astounded by this notion of packages being (essentially) completed, but it really is the case. Many of the most used packages see very few commits, often "non-code" changes like fixing typos in docs.
I rather look at open issues and PRs as an indicator of the state of a Clojure package: high numbers could mean that there are significant issues with it that are not being addressed.
That makes sense. I wonder if the immutable nature inherent in clojure results in more robust packages, thereby removing the need for constant debugging and commits.
Is there a name for a function that creates a function, like a builder or factory? I'm thinking of something that follows this pattern:
(defn make-something []
(fn [request] {:status :ok}))
Any function in Clojure will happily do this for you, obvious question is why / what's the use case?
Thanks, @martin. I didn’t know if there were different names for higher-order functions that take in function arguments, vs functions that return functions. I guess not! @UK0810AQ2 - I did this in my Advent Of Code solution, but I also see them all the time in Reitit code, for instance.
@U01HHBJ56J1 take a look at malli, too, it's full of them. There's really no difference between a factory and a higher order function in this sense. Moreso, with Clojure functions just being class instances, I find it amusing. You can call it a factory function and no one will look at your weird
I have a long list of calculation that take quite some time but I can simply map
over the inputs and collect the result
sometimes though one of these calculation might fail but i still want to keep the other results
(map #(try (calculation %) (catch Throwable t t)) data)
would give you results where the calculation succeeds and exceptions where it failed.
Then you can either (remove #(instance? Throwable %) results)
or report on the failures or whatever you wanted.
ah yeah i should have thought of that before I started the calculation again 😄
thanks sean
what if instead I wanted to "stop" the map
on the first exception? would you use something like take-while
?
I would've used an atom to store intermediate results like:
(run! #(swap! *storage-atom conj (calculation %)) data)
or something like it.
(the atom should probably be a vector as an initial value: (def *storage-atom (atom []))
)
I don't think an atom helps here at all
with reduce
you can use reduced
to stop early
(reduce (fn [results input] (try ... (catch Exception _ (reduced results)))) [] inputs)
you can do similar with loop
but I think reduce makes it easier to understand
oh nice!
(defn parse
[inputs]
(reduce (fn [results input]
(try (conj results (Long/parseLong input))
(catch Exception _
(reduced results))))
[]
inputs))
(ins)user=> (parse ["1" "2" "3" 4 "5"])
[1 2 3]
yeah reads very nicely
thanks for the explanation
I also was thinking some kind of mutable thing like @hobosarefriends mentioned
If you insert a try-catch inside of the mapping function you can even keep going through all of them if one fails it can return nil or something recognizable to filter them out.
that's true - keep
is like map
except it ignores nil
and map
is simpler than reduce
- I only suggested reduce because it looked like early exit was wanted
yeah that was exactly what I meant in my second question
but I think what @hobosarefriendssuggested was like let it explode and all the previous calculation will still be in the atom
(let [*storage-atom (atom [])]
(run! (fn [x] (try
(swap! *storage-atom conj (calculation x))
(catch Exception _ nil)))
data)
@*storage-atom)
but yeah the other one would exit early as well, because it throws an error.. I wouldn't call it graceful, but it definitely works 😅don't do that :)
(`run!` is implemented as reduce
that ignores the accumulator. so it makes a lot of sense to use reduce and not ignore the accumulator rather than introduce another accumulator in an atom)
also if your goal is not to stop at an exception, just use
(keep (fn [x] (try (calculation x) (catch Exception _))) input)
the returning nil is implicit, and keep skips the nils
I recommend taking everyone else's advice over mine, they have good reasons for recommending against it. (and much more experience) My solution is merely a quirk, because I have an easier time reasoning about it with atoms.
atoms let you solve things the way a classic algorithms book would :D
yeah i see where you come from
but I think most here would agree it's worth the extra effort to learn the immutable constructs (and learn how they substitute for the classic mutable patterns)
for me force of habit makes me reach for mutable stuff
but when stuff is simple I hear a voice "Clojure has probably a better way to do this.."
Hi, is there a way to partially load a file? For example, I converted an 8.8MB XML file to a 180 MB edn file 😅 And I'd like to load just some portion of it for examination. 1. Possible to do this? 2. Possible to do this without breaking things?
checkout iota/vec
from https://github.com/thebusby/iota for random access.
I think the harder part is reading parts of an edn file as clojure data structures without loading the whole thing
(you didn't explicitly say that was needed but it seems like that would be part of the task)
It's just too big to load into a text editor without bringing my machine to a crawl, I don't know how to start funking around with it
there are editors that don't load the entire file into RAM - eg. sam (which is very old and weird) - I wonder if there are any newer ones
So I'm trying to use :post
assertions to be sure that a function is returning valid values. It's failing but I'm trying to figure out if I can see the value that failed. I'm new to spec and I'm not sure if I have a problem with my logic or my spec definition.
(defn flow-efficiency
"Calculate flow efficiency for a single issue"
[issue]
{:post [(s/valid? :flow/flow-efficiency %)]}
(let [active-time (active-time issue)
flow-time (flow-time issue)]
(if (= 0 flow-time)
0
(float (/ active-time flow-time)))))
I get the following error:
; error: java.lang.AssertionError: Assert failed: (s/valid? :flow/flow-efficiency %) (core.clj)
Which tells me where it failed, but doesn't really help me understand what happened.What does the s/def :flow/flow-efficiency look like?
What's the cleanest way to express something like:
(foo 1 2 3 4)
(bar 1 2 3 4)
Is there something more idiomatic than just keeping it as is or using:
(map #(% 1 2 3 4) [foo bar])
Not really. I just see myself apply the same arguments to a set of functions often enough that I wonder if there's a better expression for it... kinda like a reverse partial
or something?
Are those function calls all happening within the scope of another function you have defined?
So, why not capture the relevant parameters in a list bound to a symbol (say, baz) and then just apply the functions to that parameter list?
That way it's clear you expect the function applications to happen on identical parameter values…
Don't you have to apply
the args
so it gets passed in as separate items instead of as a collection?
you need it
apply, that is, you need it
the earlier examples @alex.sheluchin gave has positional args instead of a collection
if it's just two, and I really wanted to make sure the args stay in sync, I'd do let with apply
but if it's an unknown number of functions to call with the args, or more than two, the map is good
I'm not sure https://clojurians.slack.com/archives/C053AK3F9/p1638478479270500 is better than just repeating the args in two calls. map
is okay, but I still feel like there's some function I'm not aware of made just for this 🙂
it's better than repeating the args if you really want to make sure the args stay in sync across calls
@erp12 my question is not specific to a particular use case right now, so if there are different answers here depending on side-effectfulness, I'd like to understand both sides.
you're not doing anything with the result of the first call, so the assumption is you're doing it for the side effects
side effects can include just printing things out
Yup, what @corasaurus-hex said. Also I wanted to raise the usual warning about lazy evaluation using map
and similar iteration functions.
For example, if your functions are something like: log-to-file
and println
, you should use doseq
instead of map
so that you can be sure the side effects actually happen.
I think I understand that common point of caution around laziness well enough. I usually just define the iteration with stuff with for
and consume it with reduce
or doseq
if I need side-effects. I haven't yet familiarized myself with dorun
, doall
, run!
, etc.. I thought there might be something hiding there that would be the answer for my question.
you mentioned a reverse partial
maybe something like
(defn reverse-partial [& args]
(fn [f]
(apply f args)))
(def rp (reverse-partial 1 2 3 4))
(rp -)
(rp +)
The framing of my question was bad. How about this:
(let [x (foo 1 2 3 4)
y (bar 1 2 3 4)]
...)
@antbbn thanks. I was thinking something along those lines too, but I don't feel like it simplifies anything here unless it's a common enough pattern in the codebase to merit a helper function.
https://clojuredocs.org/clojure.core/juxt:
(let [[x y] ((juxt min max) 1 2 3 4)]
(println x y))
1 4
=> nil