This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-04
Channels
- # announcements (28)
- # asami (12)
- # aws (3)
- # babashka (69)
- # babashka-sci-dev (34)
- # beginners (52)
- # biff (3)
- # calva (20)
- # clj-kondo (4)
- # cljsrn (4)
- # clojars (1)
- # clojure (90)
- # clojure-czech (2)
- # clojure-europe (33)
- # clojure-nl (11)
- # clojure-norway (35)
- # clojure-seattle (1)
- # clojure-uk (5)
- # clojurescript (87)
- # cursive (10)
- # datascript (5)
- # datomic (35)
- # defnpodcast (1)
- # emacs (8)
- # events (4)
- # fulcro (1)
- # google-cloud (2)
- # graphql (2)
- # hispano (2)
- # honeysql (5)
- # hoplon (2)
- # hugsql (1)
- # jobs (7)
- # kaocha (9)
- # lsp (102)
- # meander (13)
- # observability (7)
- # off-topic (56)
- # overtone (2)
- # pathom (47)
- # podcasts-discuss (1)
- # rdf (30)
- # reagent (16)
- # reitit (1)
- # releases (2)
- # remote-jobs (26)
- # rewrite-clj (10)
- # tools-deps (4)
- # vim (5)
- # vscode (4)
- # xtdb (41)
Is there a way to have a function that takes positional or named arguments? I'm thinking like:
(defn foo
([& {:keys [a b]}] (foo a b))
([a b] (+ a b)))
(foo 1 2)
;;=> 3
(foo :b 2 :a 1)
;;=> 3
(foo {:a 1 :b 2)
;;=> 3
Hum... fair, though in my case both are mandatory, I guess if there was a way to tell Clojure about that it could be distinguished
Similarly, Clojure could know that :b
is just my label, and so that will always be hard-coded at call-site, so it could also know from that
You could employ the JS technique to count the arguments. :D But I myself would rather just not use &
at all.
So part of what's going on here is that when you use the & {:keys [a b]}
syntax there's nothing special about the keys :a
and :b
from Clojure's perspective. It just wants to collect a map from arbitrary keys to arbitrary values, and there are no "required" keys to make a map.
All that's happening is that the arguments are being poured into a map and then you're using a shorthand syntax to bind the symbols a
and b
to the matching keywords from the map.
And while potentially you could make the clojure compiler care about these, it would be a breaking change unless a brand new "type" of defn were introduced, which seems unlikely at this point.
Well it would be breaking in this case if the compiler started to treat keys specified as required. Also I want you to keep in mind that you couldn't treat them as interchangeable in many cases, because Clojure focuses a lot on higher order functions, and you don't know if it will be called with named arguments or positional ones until it's actually called.
Ah ya, that one would. But I wasn't thinking it changed to always be required. You'd tag them as so explicitly. I think the other approach is better anyways. The compiler should just be aware of the keys, and if it sees them used in a call it can figure out where to dispatch. It does mean the compiler has to be fancier to track that, but I think that's non breaking and also would speed up dispatch since it can be determined at compile time.
Basically, if you see any call to that method that passed a static keyword as argument at the call site which is one of those keys, you'd know to call the positional one.
I mean you can provide this yourself with Clojure's :inline
metadata.
Something like this, for example:
could pretty easily write a macro to generate this code.
Could even extend it to give default values to the different arguments in case a named argument is left off, etc.
The point is though that these sorts of changes are definitely a different interface from defn
, and should be treated that way, because there's parts of this that just breaks existing usage. This doesn't just make legal some things that weren't legal before.
Interesting use of inline, I haven't used inlining yet for anything so I might need more time to parse it all. Frankly, I trust you that it possibly is breaking, I've only put limited thoughts into it. My current thoughts were that you could do something like:
(defn foo
([a b] (+ a b))
([& {:keys [a b]}] (foo a b)))
And defn could capture that in the second case :a and :b could be used used for named arguments, in the way 1.11 supports.
So if I call:
(foo 1 2)
Clojure knows that can't be a call to the named one, because there's no argument equal to :a or :b.
Where as if I call:
(foo :a 1)
It knows to call the named one, because it sees that one of the argument is :a
Yeah, I get what you intend, and you can have that behavior already with basically what I just did. You'd just need to write a macro that expands to it.
Maybe it's due to Clojure 1.11, before I'd just do:
(defn foo
([{:keys [a b]}] (foo a b))
([a b] (+ a b)))
(foo 1 2)
;;=> 3
(foo {:a 1 :b 2})
;;=> 3
But now with 1.11, I also want the cool new named arg style of calling, seems I can't get the best of both.does anyone know if Clojure works with Quarkus https://quarkus.io/ ? I would like to work on Keycloak and implement some functionality in Clojure. I will probably end up trying that but was curios if there is any prior work. Also if you are interested, please let me know and I will share the progress.
Or a simpler explanation: https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/
Strictly speaking it's how BINARY represented floating-point arithmetic works
I guess I'm confused though, if 100.34 isn't representable as a decimal of limited precision, why does it print it when I type 100.34 ?
That last one is explained in the second link I shared. I.e. for displaying literal values that can't be represented properly as binary there is a fudge based on the bits available in the representation to display the value AS IF we could represent it. I suspect the same is true of the 0.34 example
It you want to carry out decimal calculations without losing precision AND you can cope with a fixed decimal point representation (i.e. a precision of n decimal places) you can use BigDecimal
The literal representation in Clojure is an M
on the end of the literal value. E.g.
(- 300.34M 200)
=> 100.34M
P.S. I could have put an M
on the end of both the 100.34
and the 200
but I was lazy... Clojure converted 200
(a long) into BigDecimal for me
user> (type (- 300.34 200))
java.lang.Double
user> (type (- 300.34M 200))
java.math.BigDecimal
user> (.scale (- 300.34M 200))
2
user> (.precision (- 300.34M 200))
5
I.e. this calculation has returned a BigDecimal with a scale (decimal places) of 2 and a precision of 5 (3 digits to left of decimal place and 2 after)
BTW this is the reason financial institutions often represent monetary values as integer values and assume the 2 decimal places for the pennies/cents or whatever the currency subdivision is for a decimal currency
Not looking forward to having to divide by 240 when the UK Tory government decides to bring back pre decimal currency! 😂 😉
@U0K064KQV Just round to two decimals and pocket the difference! With all those bits you will be rich in no time.
Strictly speaking it was rounding the fractions of a penny from interest payments.
Also mentioned in one of a Science Fiction book series on a character calling himself the Stainless Steel Rat by Harry Harrison.
I have heard that most/all countries have either laws, and/or strict accounting rules, about such things.
Using rewrite-clj
I’m trying to append a list to the root node, without success
(require '[rewrite-clj.zip :as z])
(let [x "(defn foo [] 42)"
zloc (z/of-string x)]
(-> zloc
(z/insert-right '(foo))
z/sexpr))
desired output (defn foo [] 42) (foo)
. Any suggestion?You’ll get answers here and crossposting is frowned upon, but there's also #rewrite-clj
In one of his talks Rich goes on about how thinking about DB records as different types of entities and arriving at an ORM-like thing as a result is the wrong approach. I can't seem to find it in the transcripts. Does anyone recall where it's from?
https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/EffectivePrograms.md probably
@U07S8JGF7 yes, I think that's the one. Thanks!
Guys, i am kinda new here, but I have been testing/using datomic recently, and I have noticed something, whenever I start the console, to get the ui to be able to query stuff in browser, the transactor just quits on me after some time. Has this ever happened to you? What am I doing wrong?
you might want to post this over in #datomic and include some more info on version etc
I can’t seem to find #datomic, that’s why i posted it here
@U9BQ06G6T if you click on the highlighted #datomic link in the above message it should take you directly there.
Does anyone know the history of threading macros in LISP-style languages? I was surprised to find them missing in Scheme's standard library, and from a quick google search it seems like Clojure was the first language to popularize them. But how is that possible? They're so useful, surely someone was using them before Clojure. Racket has a threading
module but it was written in 2015.
ocaml has a somewhat similar syntax/operator with |> if you squint a little. But it is not really a lisp
Ok cool I'll take a look at that. I've never messed around with OCaml
It reminds me a lot of various constructs in R, particularly in the dplyr package.
That makes sense! Ty
Looking through babashka's codebase I learned that spit
can accept arbitrary data because it passes the input to str
before passing it to the java.io.Writer
. That got me wishing for spec definitions for clojure.core
functions because the spit
docstring isn't super explicit about this whereas a spec annotation from doc
would make it perfectly clear. That's probably not going to happen until spec
moves past alpha
right? It would definitely be an awesome addition to the REPL experience.
Speaking of docstrings - the lack of a convention/standard/consensus on a (opt-in obviously) docstring format intrigues/confuses me. At least in my codebase, I find docstrings and specs so frustratingly rare. Even when docstrings are written, they're often in an unstructured, incomplete or overly prose manner. I often have to read the function body (or some entire chain thereof sometimes 😿). Obviously a conventional format(s) won't stop incomplete docstrings, but they at least open the door for IDEs to offer conveniences like autocomplete block comments with parameters/return prepared, convenient hover and spelling/autocomplete help for individual parameters. Further, the mere ubiquity or presence of such structured docstrings I'd argue can coax people into adding a couple of words or a line or two about parameters or returns, when they'd previously just write a couple words about the function overall. Im thinking about javadoc and jsdoc for inspo. I might also be totally wrong and just didn't do my research about clj equivalent endeavors, but I haven't seen anything to this effect so far 😕
@stelabrego Check out https://github.com/borkdude/speculative - not sure if it has a spec for spit
but it does have a lot
But the spec would not be so interesting, as the spittable argument can be anything, so it'd be any?
probably
@borkdude Oh sick that looks awesome! Thanks Michiel. Yeah it definitely wouldn't be that interesting because don't all objects have a .toString method? The docstring could just spell out that any object is spittable but writing/reading requirements in prose is so tedious..
There's definitely much more useful functions to spec in clojure.core
See here for a fun application based on those specs: https://borkdude.github.io/re-find.web/
Wha..?? This is amazing!! I gotta see how you did this 😄
I have a talk about this: https://www.youtube.com/watch?v=Ygrml6tyrq0 It was actually my first Clojure talk ever, I believe
Just watched, that was great. Such a creative project. Self-hosted CLJS is soo cool. I really want to go to Clojure conference IRL sometime soon hopefully.
Does Clojure have a function like below? I can’t remember such one.
(if (string? open_time)
(Long/parseLong open_time)
open_time)
(foo 1)
=> 1
(foo "1")
=> 1@U3JH98J4R almost (cond-> open_time (string? open_time) parse-long)
Another instance of the cond that threads in the condition as well. Sean Corfield I believe has a open source lib with such cond.
A fif
-function is a cute addition to any codebase!
(defn fif [pred fun]
#(if (pred %)
(fun %)
%))
(def long-if-string (fif string? parse-long))
(long-if-string "1") ; => 1
(long-if-string :1) ; => :1
But a macro like you mentioned sounds neat as well, @U3JH98J4R :star-struck: