I shift to ->> whenever I’m doing a linear sequence of computations, and I lean on it more heavily in the REPL, where matching parens is a little more cumbersome. It’s usually shorter for anything over 3 function calls. :)
Jeremy, on
I think I can sort of clean an answer from how you used it here, but do you have a general guideline for when to use the ->> macro? I think that, coming from Ruby, I’d be tempted to lean on it too much.
jmartin, on
Kyle, could you recommend a good way to pick up TLA+? I looked it over once but found it dense (but maybe I dense).
venkat, on
Hi,
I am testing performance of Cassandra using YCSb. I’m using a 7 node cluster system with distributed disc. i place commitlog and SSTabke in same disc. mY issue is my read operation is to slow like 2000/sec. please can u give some suggestion
karri, on
Brilliant. Excellent series on introduction to clojure.
pseudoanonymous, on
Thanks for writing this, it is really accessible.
Will you have a concurrency chapter? I’m assuming that’s when you’ll talk about agents.
I’m really looking forward to reading the next installment.
Fabian, on
Very nice guide! So far it helped with my understanding of clojure!
I have a similar question as Adit. What is the difference between class and type? So far i haven’t found anything where they have a different return value.
From the documentation i got: “Returns the :type metadata of x, or its Class if none” When has something a :type metadata?
Mathew Bentley, on
So happy to read this guide. You are an absolute programming badass, thanks for sharing some of that with the rest of us!
Flo, on
@ Willson
Just to be clear. The Value of that Var didn’t change. With the second call (def astronauts …) you created a new var which happens to be named as the old one.
From that moment on, if you have a call to astronauts, the second definition gets evaluated.
It looks like the value changed, but that’s not the case:
(def a-value “old”)
(def a-copy a-value)
(= a-value a-copy) => true
(def a “new”)
(= a a-copy) => false
michael, on
Wow, fantastic piece of work my friend you must be very proud
Krish, on
Beautifully written.
m, on
This is wonderful. Thank you.
Pedy, on
Fantastic, great job, I got inspired too. Thanks for sharing
Andreas Olsson, on
The Code dissapers. Sorry. (def sx(atom [1 2])) (dotimes i 10)).
Andreas Olsson, on
Hello there.
I´m trying to learn some and I like your tutorial.
I have tryed changing som of youre code and got into problems.
Well I am new to Clojure. I started with “Clojure Programming” - but this introduction is just what I was looking for.
Suggested edit - “The type map relates keys to values.” perhaps could read “The type map relates a set of keys to list of values.”
Dan Haffey, on
Your description of ensure doesn’t quite match my understanding of it as an optimized version of (ref-set y @y). You wrote:
if you want to read a value from one ref and use it to update another, use ensure instead of deref to perform a strongly consistent read
Could you elaborate on why deref doesn’t suffice in (alter x + (ensure y))? Sure, deref means another transaction might modify y before we commit, but wouldn’t both deref and ensure return the value of y from our snapshot regardless? I thought it would take some additional semantic constraint relating x and y to necessitate ensure here. Just defensive programming, or am I missing something?
Are you saying that the symbol “astronauts” is always bound to the var #'user/astronauts, but that the value to which the var is bound changes from 0 to 2?
Willson, on
^ agree with above user: when I evaluate #‘user/cats in the REPL, I get back #'user/cats and NOT 5
Ahsen, on
nice tutorial, eagerly waiting for the next chapters.
Saad Mufti, on
Yikes, bitten by the markup gods, let me try that again:
Great series, I’m learning by leaps and bounds, and eagerly anticipating each chapter :-) A small correction, in your exercises section, you have:
“We can do the computation in a new thread directly, using
(Thread. (fn )
–but this simply runs the (sum-up) function and discards the results.”
First a minor point, the name of the function you defined at the top of the Exercises section is actually “sum” and not “sump-up”. Second, I don’t think this actually even runs anything, it just creates the java.lang.Thread object and passes in the Clojure function as its runnable, because all Clojure functions at the Java level implement the java.lang.Runnable interface. I think you need the following to actually run it, though of course you still need the solution to your exercise using “promise” to actually get a reference to the result:
(.start (Thread. (fn [] (sum-up 0 1e7)))
Saad Mufti, on
Great series, I’m learning by leaps and bounds, and eagerly anticipating each chapter :-) A small correction, in your exercises section, you have:
“We can do the computation in a new thread directly, using (Thread. (fn )–but this simply runs the (sum-up) function and discards the results.”
First a minor point, the name of the function you defined at the top of the Exercises section is actually “sum” and not “sump-up”. Second, I don’t think this actually even runs anything, it just creates the java.lang.Thread object and passes in the Clojure function as its runnable, because all Clojure functions at the Java level implement the java.lang.Runnable interface. I think you need the following to actually run it, though of course you still need the solution to your exercise using “promise” to actually get a reference to the result:
(.start (Thread. (fn ))
Aphyr, on
Thanks for the correction, Edward. Fixed! :)
Andy Dwelly, on
This is great. I hope you’ll consider publishing this set of posts as a book when you are done (ideally a kindle one AFAIC). I’d buy it - it’s far more readable and to the point than other beginner guides.
Edward Cho, on
Doh, Markdown? That should be:
(cut)
(binding [*board* :cedar] (cut))
(cut)
Edward Cho, on
Kudos to your effort, this is great work!
I just have a minor correction in your dynamic vars example. The binding call should rebind board instead of board. E.g.
I stumbled upon this tutorial via your superb talks on distributed systems.
Now I’m learning Clojure and currently going through “The joy of Clojure” book.
IMHO, recur would fit so nicely within the recursion topic. It’s interesting because I never came across something similar in Java, Scala nor (of course) in JS (maybe it’s there somewhere, but it’s certainly not widely used).
P - able to partitioning
C - consistency
A - availability
all distributed systems have P, but they can’t to be fully A and C both.
if data is not very urgent we can sacrifice consistency and use AP system, and otherwise.
Scott Feeney, on
Hey, great tutorial! I’ve been programming Clojure for a little while, but I’m always looking for resources I can point people to who want to learn, and this is perfect. You also mentioned a few neat functions I didn’t know about (split-with, map-indexed, reductions, and reduced).
If you’ll pardon my nitpicking, I believe the solution to the problem under “Putting it all together” is incorrect. You state the problem as relating to “consecutive pairs of the first 1000 odd integers”, but your code operates on “the first 1000 consecutive pairs of odd integers”. That is, you include the pair ‘(1999 2001), even though 2001 is the 1001st odd integer. This could be fixed either by changing the problem statement, or by moving “(take 1000)” before/inside the “(partition …)”, yielding the answer 1331333001.
I shift to
->>whenever I’m doing a linear sequence of computations, and I lean on it more heavily in the REPL, where matching parens is a little more cumbersome. It’s usually shorter for anything over 3 function calls. :)I think I can sort of clean an answer from how you used it here, but do you have a general guideline for when to use the ->> macro? I think that, coming from Ruby, I’d be tempted to lean on it too much.
Kyle, could you recommend a good way to pick up TLA+? I looked it over once but found it dense (but maybe I dense).
Hi, I am testing performance of Cassandra using YCSb. I’m using a 7 node cluster system with distributed disc. i place commitlog and SSTabke in same disc. mY issue is my read operation is to slow like 2000/sec. please can u give some suggestion
Brilliant. Excellent series on introduction to clojure.
Thanks for writing this, it is really accessible.
Will you have a concurrency chapter? I’m assuming that’s when you’ll talk about agents.
I’m really looking forward to reading the next installment.
Very nice guide! So far it helped with my understanding of clojure!
I have a similar question as Adit. What is the difference between class and type? So far i haven’t found anything where they have a different return value.
From the documentation i got: “Returns the :type metadata of x, or its Class if none” When has something a :type metadata?
So happy to read this guide. You are an absolute programming badass, thanks for sharing some of that with the rest of us!
@ Willson Just to be clear. The Value of that Var didn’t change. With the second call (def astronauts …) you created a new var which happens to be named as the old one. From that moment on, if you have a call to astronauts, the second definition gets evaluated. It looks like the value changed, but that’s not the case: (def a-value “old”) (def a-copy a-value) (= a-value a-copy) => true
(def a “new”) (= a a-copy) => false
Wow, fantastic piece of work my friend you must be very proud
Beautifully written.
This is wonderful. Thank you.
Fantastic, great job, I got inspired too. Thanks for sharing
The Code dissapers. Sorry. (def sx(atom [1 2])) (dotimes i 10)).
Hello there.
I´m trying to learn some and I like your tutorial. I have tryed changing som of youre code and got into problems.
this code works with #{} but not with []… why?
(dotimes i 10))
If you dont try you never learn… =)
Well I am new to Clojure. I started with “Clojure Programming” - but this introduction is just what I was looking for. Suggested edit - “The type map relates keys to values.” perhaps could read “The type map relates a set of keys to list of values.”
Your description of
ensuredoesn’t quite match my understanding of it as an optimized version of(ref-set y @y). You wrote:Could you elaborate on why
derefdoesn’t suffice in(alter x + (ensure y))? Sure,derefmeans another transaction might modifyybefore we commit, but wouldn’t bothderefandensurereturn the value ofyfrom our snapshot regardless? I thought it would take some additional semantic constraint relatingxandyto necessitateensurehere. Just defensive programming, or am I missing something?Correct on both counts, Saad. Fixed. :)
Thanks for a great intro series!
Quick question regarding your astronaut example:
user=> (def astronauts []) #‘user/astronauts user=> (count astronauts) 0
user=> (def astronauts [“Sally Ride” “Guy Bluford”]) #'user/astronauts user=> (count astronauts) 2
Are you saying that the symbol “astronauts” is always bound to the var #'user/astronauts, but that the value to which the var is bound changes from 0 to 2?
^ agree with above user: when I evaluate #‘user/cats in the REPL, I get back #'user/cats and NOT 5
nice tutorial, eagerly waiting for the next chapters.
Yikes, bitten by the markup gods, let me try that again:
Great series, I’m learning by leaps and bounds, and eagerly anticipating each chapter :-) A small correction, in your exercises section, you have:
“We can do the computation in a new thread directly, using (Thread. (fn )
–but this simply runs the (sum-up) function and discards the results.”
First a minor point, the name of the function you defined at the top of the Exercises section is actually “sum” and not “sump-up”. Second, I don’t think this actually even runs anything, it just creates the java.lang.Thread object and passes in the Clojure function as its runnable, because all Clojure functions at the Java level implement the java.lang.Runnable interface. I think you need the following to actually run it, though of course you still need the solution to your exercise using “promise” to actually get a reference to the result:
(.start (Thread. (fn [] (sum-up 0 1e7)))Great series, I’m learning by leaps and bounds, and eagerly anticipating each chapter :-) A small correction, in your exercises section, you have:
“We can do the computation in a new thread directly, using (Thread. (fn )–but this simply runs the (sum-up) function and discards the results.”
First a minor point, the name of the function you defined at the top of the Exercises section is actually “sum” and not “sump-up”. Second, I don’t think this actually even runs anything, it just creates the java.lang.Thread object and passes in the Clojure function as its runnable, because all Clojure functions at the Java level implement the java.lang.Runnable interface. I think you need the following to actually run it, though of course you still need the solution to your exercise using “promise” to actually get a reference to the result:
(.start (Thread. (fn ))
Thanks for the correction, Edward. Fixed! :)
This is great. I hope you’ll consider publishing this set of posts as a book when you are done (ideally a kindle one AFAIC). I’d buy it - it’s far more readable and to the point than other beginner guides.
Doh, Markdown? That should be:
(cut) (binding [*board* :cedar] (cut)) (cut)Kudos to your effort, this is great work!
I just have a minor correction in your dynamic vars example. The binding call should rebind board instead of board. E.g.
(cut)
(binding board :cedar)
(cut)
I stumbled upon this tutorial via your superb talks on distributed systems. Now I’m learning Clojure and currently going through “The joy of Clojure” book.
IMHO,
recurwould fit so nicely within the recursion topic. It’s interesting because I never came across something similar in Java, Scala nor (of course) in JS (maybe it’s there somewhere, but it’s certainly not widely used).BTW, inspiring tutorial intro.
leaf, check this repo: https://github.com/aphyr/jepsen
Tanios, read here: http://henryr.github.io/cap-faq/
P - able to partitioning C - consistency A - availability
all distributed systems have P, but they can’t to be fully A and C both. if data is not very urgent we can sacrifice consistency and use AP system, and otherwise.
Hey, great tutorial! I’ve been programming Clojure for a little while, but I’m always looking for resources I can point people to who want to learn, and this is perfect. You also mentioned a few neat functions I didn’t know about (split-with, map-indexed, reductions, and reduced).
If you’ll pardon my nitpicking, I believe the solution to the problem under “Putting it all together” is incorrect. You state the problem as relating to “consecutive pairs of the first 1000 odd integers”, but your code operates on “the first 1000 consecutive pairs of odd integers”. That is, you include the pair ‘(1999 2001), even though 2001 is the 1001st odd integer. This could be fixed either by changing the problem statement, or by moving “(take 1000)” before/inside the “(partition …)”, yielding the answer 1331333001.
Bonus points for juxt. ;-)