This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-04-25
Channels
- # announcements (3)
- # aws (6)
- # beginners (143)
- # boot (14)
- # calva (2)
- # cider (1)
- # clara (1)
- # clj-kondo (1)
- # cljdoc (4)
- # cljs-dev (50)
- # cljsrn (5)
- # clojure (61)
- # clojure-chicago (1)
- # clojure-europe (4)
- # clojure-italy (5)
- # clojure-nl (5)
- # clojure-spec (32)
- # clojure-uk (11)
- # clojurescript (166)
- # clojureverse-ops (2)
- # clr (3)
- # core-typed (1)
- # cursive (8)
- # datomic (21)
- # defnpodcast (1)
- # emacs (1)
- # figwheel (1)
- # figwheel-main (1)
- # fulcro (7)
- # graphql (7)
- # jobs (8)
- # leiningen (4)
- # luminus (3)
- # lumo (17)
- # mount (3)
- # nrepl (4)
- # off-topic (113)
- # pedestal (1)
- # re-frame (15)
- # reagent (2)
- # reitit (2)
- # shadow-cljs (75)
- # spacemacs (3)
- # sql (12)
- # tools-deps (44)
- # uncomplicate (2)
- # xtdb (15)
i want to have clojure files that I load dynamically, I want each to give different implementations of the same interface (forgive the OO terminology). @mail462 pointed me to using multimethods, however, I'm not seeing how I load a given file and start using it's implementation vs. another file w/it's different implementation.
@joel380 check out this minimal sketch https://gist.github.com/arbscht/f970fb921e50aed2a4563d1c0b8687d2
OK, so part of the trick there is knowing what keyword they supported. Not to be difficult, but is there a way to basically ask what they support?
Of course there is. run (doc methods)
in your REPL.
In my case, i want to know what the implementation is for (what "event") so that i can use it when that even happens.
not sure about that but it seems on the surface like having to know such detail would defeat the purpose...
if you encounter an event in the wild, all you need to do is invoke, say, (handle-my-event <some-distinct-property-of-the-event>)
note that the dispatch fn in my example is (fn [meal-time] meal-time)
but you can do all sorts of things there to detect properties of your event
so if you invoked (handle-my-event <the-event>)
then your dispatch fn could extract a distinct property of it (say, event name or type) and return that. then you only need to define defmethods for those possible values
How are these expressions different?
user=> (#(Boolean/valueOf ^String (or % "true")) true)
true
user=> (#(Boolean/valueOf ^String %) (or true "true"))
Execution error (ClassCastException) at user/eval42858$fn (form-init549726585980450320.clj:1).
java.lang.Boolean cannot be cast to java.lang.String
I'd expect it's because the reader attaches ^String
to the next form read, not the next value. so in the first case ^String
attaches to the form (or ..)
, but that evaluates to an untagged value true
-- equivalent to (#(Boolean/valueOf %) ...)
(no type hint at all). in the second case, ^String
attaches to %
, i.e. tagging it, which hints the typed dispatch, and yields a class cast exception with true
as the value
Ahhh okay. So the part of my mental model that was wrong, was that I expected that the tag would propagate with the form (as it gets evaluated) or that it was attached to the actual value.
So in this case, (#(Boolean/valueOf ^String (or % "true")) true)
, having the annotation is irrelevant?
I think so. you can make it relevant by attaching it to the identifier %
: (#(Boolean/valueOf (or ^String % "true")))
indeed
'(#(Boolean/valueOf ^String (or % "true")) true)
'(#(Boolean/valueOf ^String %) (or true "true"))
'(#(Boolean/valueOf (or ^String % "true")) true)
((fn* [p1__14629#]
(Boolean/valueOf ^{:tag String} (or p1__14629# "true"))) true)
((fn* [p1__14632#]
(Boolean/valueOf ^String p1__14632#)) (or true "true"))
((fn* [p1__14635#]
(Boolean/valueOf (or ^String p1__14635# "true"))) true)
Two last expressions generate this casting code.
final String s = (String)o;
this = null;
return Boolean.valueOf(s);
While first expression type hint is irrelevant and generates reflective code. Where o is a result object of (or) s-form evaluation.
args[n] = o;
return Reflector.invokeStaticMethod(classForName, methodName, args);
(eval ^String (or true "string"))
=> true
(meta (eval ^String (or true "string")))
=> nil
@UH16CGZC2 how do you see the generated code?
why is this bool acceptable, but a plain true
is not?
user=> (#(Boolean/valueOf ^String (or % "true")) true)
true
user=> (type (or true "true"))
java.lang.Boolean
edit: Any way to speed up reductions
in a similar way to how clojure.core.reducers
optimizes everything?
I know Clojure is not really the ideal language to implement primitive math and numeric algorithms in, but I’ve been having a lot of fun lately trying my hand at translating a bunch of number theory algos into a functional style. Most end up looking good and working well—not as fast as the equivalent C implementation, of course, but a lot easier on the eyes.
Anyway, I’ve spent the better part of this week trying to understand and implement the Pollard-Brent algorithm (an extension of the Pollard rho algorithm). After 5 rewrites (including a couple terribly imperative/mutative ones with atom
s and @
s all over the place), I finally have something that is functional (in both senses of the word).
BUT… it’s very very slow. Given the same test values, this takes 4 minutes to factor a ~45-digit number vs. the Python implementation, which takes 3 seconds (!!!).
Is there anything I can do to fine-tune this code while keeping the functional style? (Everything is included in the gist, including the test values and Python code)
https://gist.github.com/52e3ee425ca5930894f1efa20fb451f7#file-brent-clj
Have you tried type hints for the numbers? E.g. https://www.reddit.com/r/Clojure/comments/9swnsq/why_mathabs_is_so_slow/e8s49js/
Ah, good idea. Well, I just put a bunch in but it didn’t make a difference. I think the only functions that could make use of them are tower/abs
and tower/gcd
. My mod-pow
and mod-mul
functions don’t have any provisions for them (though I added type hints to those calls anyway)
So I hacked and chopped up the function a bit to figure out the bottleneck and the calculation of the qs
is a huge bottleneck
And I changed mod-mul
to *'
just to see if it was my function’s fault, but it seems to be the reductions
I tried to rewrite reductions
using r/reduce
but it didn’t help
(defn rdns
[rf init coll]
(r/reduce (fn [res b]
(let [a (peek res)]
(conj res (rf a b))))
[init] coll))
😅 You know what ended up yielding a pretty big speedup? Replacing my own mod-mul
function (which uses bit shifting and all) with plain old built-in *'
and mod
It might be worth asking on Reddit, optimisation questions there seem to get a lot of responses 😉
all that ! thing is not clear for me either, i've heard Stuart Sierra doesn't like it
i guess we use it do differentiate between mutable \ immutable - blocking \ non-blocking operations if there is ambiguity present
but i need confirmation for myself from more experienced developers, probably someone from cognitect?
well clojure IS a lisp, there is no such thing as "Lisp language" rather lisp dialects, as i see it
it's definitely documented in the Scheme spec >By convention, the names of procedures that store values into previously allocated locations (see section 5.10) usually end in “!”
That is not going to happen for functions in core, I am 99.9% sure.
which is kinda half measure, just to keep core lib function names more uniform as i see it
I think I've heard folks say that !
should apply to io too, but I think if everyone conformed to that standard we'd see a lot more bangs everywhere.
should use those more 😄 https://en.wikipedia.org/wiki/APL_syntax_and_symbols
lol if you want side effects, you should want it enough to use a non-standard character 🙂
depending on who you ask, !
means "impure", "unsafe in a transaction", or just "beware"
also impure/unsafe in a transaction are mostly the same thing, depending on how you feel about erroneous logging / printing
the number of !'s tells you how many times you should consider alternatives before committing to this design choice
actually, think 3 times
Is http://clojuredocs.org/clojure.core/io! used much in the wild?
I inherited its use in clojure.java.jdbc
inside the JDBC transaction code and I've just sort of kept it there (and it's in the equivalent in next.jdbc
now). I've never seen it used anywhere else TBH.
(the discussion about !
made me think about it -- because clojure.java.jdbc
uses !
on functions that are expected to perform database updates -- but next.jdbc
has only reducible!
, execute!
, and execute-one!
since they could all perform database updates)
io!
is specific to STM transactions and seems like a good idea but I've never seen it used (outside that one place).
so swap!
doesn't check for it?
Nope:
user=> (def a (atom 0))
#'user/a
user=> (swap! a #(io! (inc %)))
1
(no transaction there -- only with refs)
At least, that's my understanding of when io!
is checked.
I've always been surprised that alter-var-root
does not have !
(but alter-meta!
does... and alter
itself does not).
I think it’s safe only to say that ! is used inconsistently
Pretty dumb question. I have sets of suits and card ranks (like in the spec guide). I am trying to make a vector of cards taht looks like [{:suite :spade, :rank 7} {:suite :diamond, :rank :ace}]
I have a code that looks like this:
(def suit? #{:club :diamond :heart :spade})
(def rank? (into #{:jack :queen :king :ace} (range 2 11)))
(def cards (reduce (fn [new-cards [rank suit]]
(into new-cards [{:suit suit :rank rank}]))
[]
(for [suit suit? rank rank?] [rank suit])))
There has to be a better way to do that...
Yeah...that was taken straight from the spec guide.
They use s/valid? suite? :diamond)
kinda stuff. I think that's why they have the ?
Well now I feel silly.
I've been reading Clojure for Brave and True and they don't mention for
at all. So I'm used to using reduce for everything.
i'm not a huge fan of for
either. but if you already have the combinations then you are basically done 🙂
Is there a different way to cross those two seqs like they've done with the for
(let [cards (fn [suit]
(map (fn [facecard] {:suit suit :card facecard}) cards))]
(mapcat cards suits))
(map #(hash-map :suit %1 :rank %2) suit? rank?)
A lot of times, I think for
reads more clearly than map
but there's always that nagging confusion with for-loops in other languages whereas it's a for-comprehension in Clojure...
i just always forget how it works with multiple bindings. if its like map over two collections or if it gives permutations
Oh, right. Yeah, then for
is definitely "better" in this case. IMO.
(I was just focused on trying to get rid of your mapcat
🙂 )
Is there an easy way to write a checker in midje like throws
that checks for slingshot throw+
exceptions?
Hello all!
Is there any update on this? https://dev.clojure.org/jira/browse/CLJ-1899
It's Add function transform-keys to clojure.walk
There's nothing on that ticket since 2016 so, no updates.
Am I asking for trouble if I install Clojure command line tools somewhere else than the default /usr/local? I was wondering that after Clojure 1.10 if I want to install Clojure cli 1.11 and keep 1.10 around I can't install them to /usr/local. E.g. I usually install all my Java versions to /mnt/local/ (i.e. /mnt/local/jdk8, /mnt/local/jdk9... and add those to my path per project).
@kari.marttila the clojure tools are able to pull different versions of clojure
yeah, any version of the cli can run any version of clojure (despite the version number in the name)
the version number is really more an indication of vintage and also what the internal classpath-building code is using
so, in short, there is no reason to have anything but the latest installed
Ok. Good to know. So, basically I can keep the Clojure CLI tools then in the default directory /usr/local then.
Ok. Thanks for clarifying that to me.
the Clojure version you use is determined by your deps.edn
BTW. I really appreciate this community. Great people. And Clojure really blew my mind when I started to use it. I have tried to promote Clojure in my corporation - a great language.
good luck!
There seems to be Clojure gurus around - I hope you don't mind me asking one thing that has been in my mind recently.
I have read Stuart Sierra's Clojure workflow, regarding how to make Clojure application so that you are able to start / stop etc the application in repl without needing to start repl, http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded
I was wondering is this some kind of best practice how to structure Clojure application?
I mean, making the development workflow fluent with repl...
Are there some other "recommendations" or "best practices" how to structure a Clojure application and work with repl?
@kari.marttila We use Component very heavily. It's very convenient to be able to build a "system", start it, run stuff, and stop it again in the REPL. We use it in our test suites too, to spin up local test versions of servers and shut them down again after tests have run.
We don't generally use the actual "reloaded" part tho' -- we very rarely find the need to completely clean out and restart the REPL.
I start up Cognitect's REBL with a Socket REPL and connect to that from my editor (Atom w/Chlorine) and leave it running for days and days just evaluating code into it from my editor (`C-, i` and C-, I
are bound to "inspect form" and "inspect top-level form" -- which evaluates and sends the expression to REBL). I use "Rich Comment Forms" (the (comment ..)
form containing non-production code to aid development) and those often have things like
(def app (component/start (app/build-system {..})))
(component/stop app)
... other useful code ...
So I can easily spin up my application in the REPL and shut it down whenever I need.@hiredman may have additional thoughts on "reloaded" and our workflow.
Thanks! Great info! I try to use Component also in my next personal Clojure project.
There's a #component channel if you get stuck (it's low traffic so it's easy for folks like me to keep an eye on).
Ok, thanks!
And thanks also for mentioning Cognitect REBL - I didn't know that such a tool exists. http://rebl.cognitect.com/ I definitely need to try it in my next personal Clojure project.
I need to open my mouth more often in this #beginners channel - great info.
I love REBL! (there's a #rebl channel too, BTW)
I'm starting to switch from clojure.java.jdbc
to next.jdbc
at work and that supports datafy
and nav
out of the box so it's great for working with REBL since you can easily navigate through your result sets into other tables etc.
Component works well but is very flexible in it's usage so you can end up with different styles of usage. On the one end the is passing the whole system around and on the other end you pass around just components. The library itself doesn't provide guidance there and people end up at different places.
Ok. Good to know.
BTW. Can you recommend some good project in Github that uses Component (that is not too complicated - i.e. to be used as an example)?
I tend to point people at this https://github.com/framework-one/fw1-clj/blob/master/examples/usermanager/main.clj -- not because it's "good" but just because it's a fairly simple, self-contained web app + database example.
Moved to a better location and updated: https://github.com/seancorfield/usermanager-example
@U04V70XH6 thank you, this is exactly the kind of thing I need to let a new developer play with to get to grips with the bigger picture
(it doesn't even have a Component for the database setup, which it really should)
I ought to migrate it out of that repo and update it to reflect better practices...
Ok. Thanks!
What I do like about that example is that it builds the application as a component, separate from the web server component, and it uses middleware to add the application component to the Ring request hash map so it is available at the top-level for all the handler functions to access.
If it had a component for the database, as a dependency of the application, then Ring handlers could pass just that down into the model functions etc.
Ok. I need to read the example carefully before my next Clojure project.
Feel free to DM me if you have questions.
Moved to a better location and updated: https://github.com/seancorfield/usermanager-example