This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-01
Channels
- # announcements (7)
- # babashka (41)
- # beginners (117)
- # cider (3)
- # clj-kondo (145)
- # cljdoc (25)
- # cljs-dev (19)
- # clojure (197)
- # clojure-dev (14)
- # clojure-europe (4)
- # clojure-italy (3)
- # clojure-nl (2)
- # clojure-spec (11)
- # clojure-uk (21)
- # clojuredesign-podcast (5)
- # clojurescript (29)
- # code-reviews (4)
- # cursive (87)
- # data-science (11)
- # datomic (29)
- # duct (2)
- # emacs (10)
- # graalvm (1)
- # lumo (13)
- # malli (2)
- # nrepl (5)
- # off-topic (25)
- # onyx (1)
- # pathom (6)
- # reagent (20)
- # reitit (4)
- # rewrite-clj (7)
- # shadow-cljs (114)
- # spacemacs (16)
I'm using EMACS/cider and I've spec'd and instrumented a bunch of functions. The argument to a function is failing to meet the spec and cider is giving me a stacktrace. Nowehere in the stacktrace does it identify where in the code the spec failure is and that makes me think I must be doing something wrong. Symptoms:
I have a line that says: Spec: #object[clojure.spec.alpha$every_impl$reify__2254 0x46fce19 "clojure.spec.alpha$every_impl$reify__2254@46fce19"]
I have a stack trace that identifies: cityevolver.clj: 91 cityevolver/evaluate-placement-list
As the last function I wrote. It calls 3 other functions and one of them has malformed arguments
So I know that an argument has failed a spec but I get the impression something is wrong because there is no line saying "... and the spec was for arguments to [function-which-was-spec'd]"
That's interesting. It may actually be related to new clojure errror reporting. But you can try to inspect the exception manually in the REPL:
*e
what is the simplest way to change this [30.723457672119142 36.869895291987106]
to [30.7234 36.8698]
(mapv (comp float #(/ % 10000) int #(* % 10000)) [30.723457672119142 36.869895291987106])
thank you very much, somehow a similar approach of mine looked weird I was expecting some shortcut or some magical core math function 😄
Other approach using format
:
(defn round4 [n]
(Double/parseDouble (format "%.4f" n)))
(mapv round4 [30.723457672119142 36.869895291987106])
;; => [30.7235 36.8699]
(mapv round4 [30.0000001 36.000001])
;; => [30.0 36.0]
Oh wait that rounds up, if that’s a problem use another approach 🙂
And if it’s a problem you should probably use BigDecimal
Because floats aren’t precise
it was for geolocation openlayers(mapping library) gives long decimals. i don't need to be super precise. thank you
Hi everyone,
I am new to Clojure (and emacs) and I am facing this challenge.
I am following the instructions in the book/site Clojure for the brave and true
and I can't start the REPL in emacs.
when i do M-x cider-jack-in
i get
error in process sentinel: could not start nREPL server: no Java runtime present, requesting install.
I am doing this on Mac OS and I already have Java 12 installed using sdkman
I tried switching to Java 8 and got same result.
I have also tried updating my emacs packages.
Any suggestions please ?Something else though, I also started with this book. I had to start two times over in attempting to learn Clojure with this book because I always also wanted to learn using Emacs. Emacs is a great editor and maybe I'll get into it at some point. However, it does some things differently than most editors these days. Maybe that won't be an issue for you but if you feel frustrated with Emacs at some point, just throw it over board and focus on Clojure alone. Come here and find someone who can help you setting up your favorite editor/IDE for Clojure development.
This is my third attempt at getting something done with Clojure and it's my first attempt without Emacs and I'm finally getting somewhere.
Thanks a million @UPJP9G4G1
I think i will just keep emacs aside for a while and go with my familiar Intellij IDEA
Have you seen the Cursive plugin? https://cursive-ide.com/. Free for non-commercial use. Or look into Calva for Visual Studio Code: https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva For an Emacs that works out-of-the-box you can look into Spacemacs with the Clojure layer: https://github.com/syl20bnr/spacemacs, https://github.com/syl20bnr/spacemacs/tree/c7a103a772d808101d7635ec10f292ab9202d9ee/layers/%2Blang/clojure. But Spacemacs works best I think if you use the Vim-bindings, which is another thing to master.
I have another problem "4.455"
to decimal 4.455
and "3.14"
to 3.14
to do this my function became very long do you know short way?
is this in cljs or clj?
if you don't mind a "bigdecimal" you can use (bigdec "3.14")
don't use Float/parseFloat - use Double/parseDouble in that case
sorry i didn't mention that was CLJS I think we don't have Double/parseDouble in CLJS
oh, yeah I was talking about clj/java
(js/parseFloat "3.14")
should work. I haven't tested it though. Not sure about the precision though on big numbers (decimals)🙂.
yeah it works thank you. somehow I never check the hosting language. I have a bug in my brain. embarrassing 😄, thank you very much
You are welcome! Good luck ✌️ 🙂
Hi guys, I'm an iOS developer trying to learn Clojure. I have no experience with the Java world or web development. This makes it quite difficult for me to learn Clojure and make use of it as I often improve best through pet projects. Tbh I feel kinda lost rn. Can anyone recommend me a learning path or point me to the right direction? Really appreciate your help!
Hey there, I'm somewhat of a beginner myself, but was recommended this book early on in my learning (a great starting point imo): https://www.braveclojure.com/ You can read online for free or buy a e and/or physical book.
app:calculator.core=> (= js/Number (type 1))
true
app:calculator.core=> (instance? js/Number 1)
false
That's confusing to me. How do you check type in ClojureScript? Asking in this channel because it seems more beginner than ClojureScript.It's because 1
is a primitive. If you do typeof 1
you should get "number"
. However, Number
is an Object.
So, it shouldn't be possible to do 1.toString()
but you can do Number(1).toString()
. And the result of Number(1)
should be an instance of Number
Aye. I see. Then this is proper, yes?
app:calculator.core=> (instance? js/Number (js/Object. 1))
true
Hi all, I am getting started with clojure and working through the brave and true book. In the exercises for chapter 10 (at the bottom of https://www.braveclojure.com/zombie-metaphysics/), there is one where I need to get several random quotes from
in parallel and save word counts in an atom. I solved it, but I don't think my code is very idiomatic and I am trying to understand how to solve it better, can you please look at my solution and tell me how it could be improved? https://gist.github.com/passick/4d100029c217c2c9e80e8cd7f9990118
In particular, that stuff with doall
and the way I create several futures seem fishy to me. Is there a better way to do it?
Since you are using map
/`doall` purely for side-effects, run!
is probably what you want instead.
https://clojure.org/reference/reducers#_reduce_and_fold -- but note the "chunks" are 512 by default so for small collections it won't be parallel
But look at repeatedly
for invoking a no-argument (side-effecting) function a fixed number of times (instead of the first map
over range
)
And instead of #(if %1 (inc %1) 1)
you could use (fnil inc 0)
fnil
adapts a function such that if the argument(s) are nil
, the replacement value is used instead before the function is called.
So something like (run! deref (repeatedly n-quotes (fn [] (future (process-quote ,,,)))))
Ooh, didn’t find run!
and fnil
, thanks! I have tried using repeatedly
at first, but couldn’t make it work with future
, not sure why.
Thank you, will try again!
But wouldn’t (run! deref (repeatedly …))
create a future and dereference it immediately?
So the futures will be run in sequence?
I'd have to check whether repeatedly
is chunked or not. If you want real parallelization, sequences are not the way to do it in the first place.
Doesn't look chunked... so, yeah, that might well produce sequential execution...
If you want control over the level of concurrency, you pretty much have to drop down to Java and use executors etc.
I just want the tasks to be executed in parallel, that sounds like a basic thing.
I think my solution does it, no?
well, pmap
for quick and dirty
With the caveat that pmap
is almost never what you want in production code 🙂
@UJ9KCME4U Mostly because you have no control over it. When I was first using pmap
, I threw it into a few places because I wanted "more concurrency" and it produced so much parallelism that I took down our search engine servers! 🙂
@UJ9KCME4U We drop down to Java and use executors etc. That way we have a lot more control over concurrency. We also use core.async
to help a lot of processes coordinate work.
hence the "quick and dirty" :)
Yes, looks like (doall (pmap...))
should do it. The exercise asks for futures explicitly, though.
Since you don't need the result back, you could use dorun
(which doall
uses under the hood, but then returns the original collection).
I suspect Brave&True is just expecting something simple like you had in your Gist -- but it's not idiomatic nor really "in parallel" so it's all a bit hand-wavey 🙂
I see. Thank you!
I’m currently trying to create my first macro and still have some troubles…I’m trying to create a macro where I can define some bindings which are directories that should be removed in the end. The idea is basically to have a temporary directory, do something, and be sure that the directory is deleted afterwards. I tried to do it similar to the with-open
macro since it seemed similar. Here is what I currently have:
(defmacro remove-after
[bindings & body]
(cond
(= (count bindings) 0) `(do ~@body)
(symbol? (bindings 0)) `(let ~(subvec bindings 0 2)
(try
(remove-after ~(subvec bindings 2) ~@body)
(finally
(let [dir ~(io/as-file (bindings 0))]
(doseq [file (file-seq dir)
:when (.isFile file)]
(io/delete-file file))
(io/delete-file dir)))))))
However when trying it out I get something like this:
No implementation of method: :as-file of protocol: #' found for class: clojure.lang.Symbol
Does somebody know what is happening here?@christian.paling A general bit of advice for writing macros is: try to write a function to do most of it first, and then write the macro as a wrapper around calling that function. That will help remove a lot of the problems.
In the above, you're trying to introduce local bindings dir
and file
and those will be resolved to fully-qualified symbols which won't be correct. Use dir#
and file#
instead.
Yes, in macros, it uses gensym
to create uniquely named local symbols.
Yeah... for all that everyone tends to be like "Lisp! Macros! Yay!" in real-world code, macros are really very rarely used...
Stats from our codebase at work:
Clojure build/config 52 files 921 total loc
Clojure source 303 files 70109 total loc,
3170 fns, 605 of which are private,
435 vars, 28 macros, 66 atoms,
596 specs, 21 function specs.
Clojure tests 334 files 19294 total loc,
4 specs, 1 function specs.
We have some more macros in the tests but don't bother counting those. So just 28 macros compared to nearly 3,200 functions, in just over 300 files.you could start with f
where f
takes a function g
and invokes g
with a single argument which is a directory, and deletes the directory after g
finishes executing
And I think you want (io/as-file ~(bindings 0))
instead of ~(io/as-file ,,,)
at a glance...
Because (bindings 0)
is a Symbol
(as its value) so you'd end up calling io/as-file
on (essentially) 'foo
instead of the value of foo
@hiredman Yes that’s true, that would be easier. I just liked the way with-open
is doing it, and wanted to copy 😄
you are making it hard on yourself by combing the syntax rewriting and the actual computation in the macro
you can capture the computation you want as a function, and then simply use the macro to rewrite the syntax you want in to a call to that function
@hiredman and in the fn [a]
the a
would basically be all symbols of the a
vector that was passed to the with-temp-files
vector ?
you have two things going on, something producing a value (the tmp directory) and something binding that value to a name
the f function is only resposible for producing the value, the binding of the value to a name is taken care of via the construct clojure already has for that, a function