Aphyr
Aphyr, on

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
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
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
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
karri, on

Brilliant. Excellent series on introduction to clojure.

pseudoanonymous
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
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
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
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
michael, on

Wow, fantastic piece of work my friend you must be very proud

Krish
Krish, on

Beautifully written.

m

This is wonderful. Thank you.

Pedy
Pedy, on

Fantastic, great job, I got inspired too. Thanks for sharing

Andreas Olsson
Andreas Olsson, on

The Code dissapers. Sorry. (def sx(atom [1 2])) (dotimes i 10)).

Andreas Olsson
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.

this code works with #{} but not with []… why?

(def sx(atom []))

(dotimes i 10))

If you dont try you never learn… =)

Tim McCoy
Tim McCoy, on

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
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?

Aphyr
Aphyr, on

Correct on both counts, Saad. Fixed. :)

Willson
Willson, on

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?

Willson
Willson, on

^ agree with above user: when I evaluate #‘user/cats in the REPL, I get back #'user/cats and NOT 5

Ahsen
Ahsen, on

nice tutorial, eagerly waiting for the next chapters.

Saad Mufti
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
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
Aphyr, on

Thanks for the correction, Edward. Fixed! :)

Andy Dwelly
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
Edward Cho, on

Doh, Markdown? That should be:

(cut) (binding [*board* :cedar] (cut)) (cut)
Edward Cho
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.

(cut)

(binding board :cedar)

(cut)

Marko Bonaci
Marko Bonaci, on

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).

BTW, inspiring tutorial intro.

vp_arth
vp_arth, on

leaf, check this repo: https://github.com/aphyr/jepsen

vp_arth
vp_arth, on

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.

Scott Feeney
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.

anonymous
anonymous, on

Bonus points for juxt. ;-)

Copyright © 2015 Kyle Kingsbury.
Non-commercial re-use with attribution encouraged; all other rights reserved.
Comments are the property of respective posters.