This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-12-17
Channels
- # adventofcode (56)
- # announcements (1)
- # aws (6)
- # beginners (127)
- # bristol-clojurians (1)
- # calva (29)
- # cider (7)
- # clj-kondo (37)
- # cljdoc (20)
- # cljsrn (7)
- # clojure (159)
- # clojure-europe (67)
- # clojure-italy (23)
- # clojure-nl (4)
- # clojure-provo (3)
- # clojure-uk (18)
- # clojurescript (19)
- # code-reviews (59)
- # community-development (105)
- # conjure (6)
- # core-async (16)
- # core-logic (1)
- # cursive (21)
- # datomic (19)
- # defnpodcast (1)
- # emacs (8)
- # events (2)
- # fulcro (71)
- # graalvm (23)
- # jobs-discuss (1)
- # kaocha (5)
- # luminus (5)
- # meander (16)
- # nrepl (32)
- # off-topic (6)
- # pathom (159)
- # pedestal (3)
- # reagent (14)
- # reitit (8)
- # reveal (12)
- # rewrite-clj (9)
- # shadow-cljs (169)
- # spacemacs (16)
- # specter (2)
- # sql (19)
- # tools-deps (36)
- # vim (6)
What do you expers think of my solutions: https://github.com/RoelofWobben/Learning_in_public/blob/main/ground_up/src/ground_up/chapter6.clj
> Use a promise to hand the result back out of the thread. Use this > ; technique to write your own version of the future macro. you made a function for this, not a macro, if that matters
and as mentioned elsewhere, your atomSum doesn't use future correctly - it doesn't start one thread until the other completes
also, since this is #code-reviews, I would recommend not using atom
as the name for an atom
also, we don't use camelCase for clojure names, we use kebab-case
well, defmacro works differently than defn, I don't know if you actually need to use a macro for this assignment
deref
blocks the code until the future exits
if you have (let [a (deref (future ...)) b (deref (future ...))] ...)
b doesn't start until a exits
I had that but if I remember you told me to do this way because the a and b where not used error message
if you have (let [a (future ...) b (future ...)] ...)
they both run at the same time
that's not an error message, that's your linter
you still need to deref a and b, but after b is created
(let [a (future ...) b (future ...)] (deref a) (deref b) ...)
the deref here is just telling the code to wait for that block to exit (so the atom has the right total in it)
also, if you aren't using deref as a first class function, or using its optional timeout option, just use @
which expands to deref
So this is good clojure code :
(defn atomSum []
(let [atom (atom 0)
part1 (deref (future (swap! atom + (apply + (range 0 (/ 1e7 2))))))
part2 (deref (future (swap! atom + (apply + (range 0 (/ 1e7 2))))))]
(deref atom)))
the deref is blocking part2 so it doesn't start until part1 exits
you need to deref after part2 is created, or the atom will have the wrong sum
(defn atom-sum []
(let [a (atom 0)
part1 (future (swap! atom + (apply + (range 0 (/ 1e7 2)))))
part2 (future (swap! atom + (apply + (range 0 (/ 1e7 2)))))]
@part1
@part2
@a))
deref means "block this thread until that other thread provides a value"
this is not good :
(defn atomSum []
(let [atom (atom 0)
part1 (future (swap! atom + (apply + (range 0 (/ 1e7 2)))))
part2 (future (swap! atom + (apply + (range 0 (/ 1e7 2)))))]
(deref part1)
(deref part2)
(deref atom)))
what's wrong with it?
(other than the naming stuff mentioned elsewhere)
also (range 0 x)
is the same as (range x)
because you said this : and as mentioned elsewhere, your atomSum doesn't use future correctly - it doesn't start one thread until the other completes
right, you pasted a version that used deref inside the let block
oh, that looked like a paste, I didn't notice it was a preview from some plugin
https://github.com/RoelofWobben/Learning_in_public/blob/main/ground_up/src/ground_up/chapter6.clj
oh I see you had to fix the ranges too - yeah that looks better
also note that if x
is a double (like your ocde) range makes longs if you ask for (range x), and makes doubles if you ask for (range x y)
(ins)user=> (range 1e2)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99)
(ins)user=> (range 1e2 2e2)
(100.0 101.0 102.0 103.0 104.0 105.0 106.0 107.0 108.0 109.0 110.0 111.0 112.0 113.0 114.0 115.0 116.0 117.0 118.0 119.0 120.0 121.0 122.0 123.0 124.0 125.0 126.0 127.0 128.0 129.0 130.0 131.0 132.0 133.0 134.0 135.0 136.0 137.0 138.0 139.0 140.0 141.0 142.0 143.0 144.0 145.0 146.0 147.0 148.0 149.0 150.0 151.0 152.0 153.0 154.0 155.0 156.0 157.0 158.0 159.0 160.0 161.0 162.0 163.0 164.0 165.0 166.0 167.0 168.0 169.0 170.0 171.0 172.0 173.0 174.0 175.0 176.0 177.0 178.0 179.0 180.0 181.0 182.0 183.0 184.0 185.0 186.0 187.0 188.0 189.0 190.0 191.0 192.0 193.0 194.0 195.0 196.0 197.0 198.0 199.0)
and I think your code is the kind of code where long vs. double will change the result
doubles are also slower to do math on than longs are
it looks like in this case it will give the same answer, but if you use the long
function eg. (long 1e7)
you can ensure it uses integral math
it cuts the execution time in ~half
(cmd)user=> (time (long (apply + (range 0.0 1e7))))
"Elapsed time: 247.583409 msecs"
49999995000000
(ins)user=> (time (long (apply + (range 0 (long 1e7)))))
"Elapsed time: 120.047445 msecs"
49999995000000
it varies, sometimes you need floating point
but in general longs are better (more accurate, faster)
tomorrow I hope I can solve the last one of this page : https://aphyr.com/posts/306-clojure-from-the-ground-up-state