Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: Clojure by Example (kimh.github.io)
184 points by kimh on June 10, 2015 | hide | past | favorite | 35 comments


Would be awesome if interactive like the interactive SICP[0]

[0] http://xuanji.appspot.com/isicp


Woah. I've been wanting to finish SICP book along with MIT lectures and this site looks like another great addition. This gives me a boost in motivation to finish the book.

If someone ever comes up for something like this for Clojure then it would be incredibly awesome.


Whoa! ISICP looks really cool! You know, the exercise sections of ISICP remind me a lot of the interactive Clojure exercises at 4Clojure.com. 4Clojure.com has a link to the github repo of the software used to create the site.


For those who prefer learning in a more passive manner, I've found these sets of screencasts on the Clojure Koans quite useful too.

http://www.clojurescreencasts.com/koans-walkthrough/01.html


This is a great project!

I believe there's a lack of clarity in the let form explanation:

  =>(let [object "light"]
  =>  (let [object "darkness"])
  =>  (println (str "God said let there be " object)))
  God said let there be light
  nil
'object' is overwritten but only within the second let form:

  =>(let [object "light"]
  =>  (let [object "darkness"]
  =>    (println (str "God said let there be " object))))
  God said let there be darkness
  nil
or even:

  =>(let [object "light"]
  =>  (println (str "God said let there be " object))
  =>  (let [object "darkness"]
  =>    (println (str "God said let there be " object))))
  God said let there be light
  God said let there be darkness
  nil
The reason for this is the let form uses lexical scoping. In other words it creates a new frame which includes the bindings declared in the square brackets. When 'object' is evaluated its binding is looked for in the current frame, then the frame that called that frame and all the way out into the global namespace stopping when a binding is found.

See also: http://stackoverflow.com/questions/1774417/scoping-rules-in-...


This would be better for illustrating that object is not overweritten, I think:

  =>(let [object "light"]
  =>  (let [object "darkness"]
  =>    (println (str "God said let there be " object)))
  =>  (println (str "God said let there be " object)))
  God said let there be darkness
  God said let there be light
  nil


Thanks for this. I added your example with slightly different form!


Thanks for your feedback! I think I could make it better.

http://kimh.github.io/clojure-by-example/#scope


Thank you!

I agree with fnordsensei's comment about ordering. You might also think about including this example from the docs which demonstrates bindings are immediately available:

    (let [x 1
          y x]
      y)
    -> 1


If the site looks cool and slick to you, then you should give a star to https://github.com/tripit/slate which I used to create the site.

I found Slate is very easy to use and customize!!


Lovely. A nice addition would be a floating REPL to try things out as you go along, maybe at the bottom of the screen with a dash of transparency.

(I know I know, there are plenty of other ways to access a Clojure REPL!)


Clojure has always been slightly disappointing for me...

The principles behind its design are all sound and Rich Hickey deserves credit for putting in the hard thought behind it.

... but.... the reality seems to be of a really under performing language. The forums are consistently full of people with 'why is this slow?' to which the solution is always 'Give it more hints' or 'do it in a more Java like way'.

Unfortunately the Clojure stack seems not to have much mechanical sympathy (despite its best intentions). It seems the natural/idiomatic way to use Clojure results in far too much dynamic behavior to be performant. Clojure may scale well, but its inherent bad performance (without lots of work) is a major downside.

I forget who said this, but it seems very appropriate to Clojurists... "Show me you can use one machine well before you get another..."


In my experience, Clojure performs rather well. I used to use Python for what I now use Clojure and it seems to outperform that.

Sure, Java and C++ perform better still. I don't feel like Clojure is trying to compete with them on performance, rather Clojure is competing with the dynamic languages and allows you to drop down to lower levels (type hints, Java interop) when you do need more performance. Developer productivity first, performance second.

If I need C++ performance, then I use C++ because few languages can compete with that, but for most of my work (web development), I don't need to.


Unfortunately the Clojure stack seems not to have much mechanical sympathy (despite its best intentions). It seems the natural/idiomatic way to use Clojure results in far too much dynamic behavior to be performant. Clojure may scale well, but its inherent bad performance (without lots of work) is a major downside.

This is simply untrue for most applications. I've been using Clojure and ClojureScript in production for more than two years now on a web app (front-end CLJS, back-end Clojure) and I've never had problems with it being sluggish for what I've needed to do.

When something isn't performing well enough, it's easy to profile and optimize, but in terms of building stuff out this is not something I have to think about; I focus on choosing the right data structures and abstractions. Of course, it's possible to slow things down simply by writing non-idiomatic code when you are first getting used to it (I speak from experience)--but that's not Clojure's fault: it's quite different from most mainstream languages and there is a learning curve.

For applications where you need performance like native Java, then sure, you need to optimize--add type hinting, use Java's mutable data structures, and more. I can't say too much about it because I'm not an expert on optimizing Clojure for high performance--I don't have to be.


>> For applications where you need performance like native Java, then sure, you need to optimize--add type hinting, use Java's mutable data structures, and more. I can't say too much about it because I'm not an expert on optimizing Clojure for high performance--I don't have to be.

This is what I'm talking about. Performance-wise, Clojure is all about scaling, not absolute performance. From my point of view (lots of low-level, embedded, real-time,DSP,C,C++, etc). I personally get appalled at the performance that is left on the table when using idiomatic Clojure (and even Java)... (Try doing an FFT in pure-idiomatic Clojure and compare to even a naive C implementation running on a lowly PIC32 or ARM...) it would be interesting what level of microcontroller your i7 is now reduced to.

I love the ideas behind Clojure and scalability is great... but when you're talking about scaling an application, make sure you're not throwing away silly amounts of performance before you scale it horizontally.


From my point of view (lots of low-level, embedded, real-time,DSP,C,C++, etc). I personally get appalled at the performance that is left on the table when using idiomatic Clojure (and even Java)

Okay, but that's a very different statement than your initial post where you wrote "the reality seems to be of a really under performing language." The value proposition for Clojure includes well thought-out high level abstractions, great built-in immutable data structures, interoperability with Java and JavaScript, all the stuff that comes with being homoiconic, and more. The value proposition for Clojure does not include programming for embedded systems, building low-level systems software, or wringing out every last bit of performance from your hardware. "Inherent bad performance," as you put it previously, is relative to the problem space you are working in.


its not a different statement, Clojure is (partially) sold as a performant language, partially thru its links to Java, partially because of 'scaling' I suppose. What I'm saying is that it isn't truly performant.

Like you say, the strong points of Clojure are the homoiconicity, immutability, STM etc. It seems to me that as soon as you attempt to use the good bits of Clojure, performance goes out of the window, which is a real shame.

BTW: I wasn't indicating I thought Clojure was intended for embedded s/w, just indicating that I have an interest in true performance, not just scalability due to my background in embedded s/w.

Don't get me wrong, I like Clojure and it has its place, but its just a shame that in order to use its strengths, you pay a big price.


I aggree. I love the language and concepts, but at some point, after two months of learning it, I've got fed up with the slugishness of the whole thing and gave up because I have no idea what to do with it.

I also found it a very difficult language to learn. I felt like I was taking baby steps every day, although I was giving it all I could. I felt stupid and frustrated to the point that I'm actually considering quitting the profession, because, well, I'm not good enough for this.

Contrast that with Objective-C which I learned last year - it took me a couple of weeks to become profficient and start writing real world, commercial apps which I can sell. Maybe 15 years of daily C++ programming has had something to do with it, but still.

I struggle to imagine a practical project which I could use clojure for.

Front end, user-facing apps, utilities, system tools - forget it - an app takes 15 seconds to load and uses gigabytes of RAM.

Backend - maybe, but there are a lot of other languages and frameworks out there which are really powerful and have huge communities.

So I don't know, I really love clojure, but the JVM just doesn't cut it for me. I want a C++ version of Clojure, which I was thinking about starting every single day I was learning it.


I appreciate your sharing your experiences. But don't give up just because you struggle with Clojure. That's certainly not a sign that you're not good enough for this profession, especially if you have 15 years of C++ experience!

Is the problem that you struggle with how to solve problems in a functional style? I can imagine that Clojure might be a tough place to start for learning FP, even though you don't have to worry about a type system such as in an FP language like Haskell. What really helped me understand functional programming (in the lispy sense, not the Haskell sense) was the free book "How to Design Programs" http://www.htdp.org/ This book taught me, for instance, how to break down problems into small blocks that use recursion, and how to compose those blocks together.

There's also a second edition that seems to be significantly more streamlined (which is probably more appropriate, given your existing experience with programming), but I haven't used it: http://www.ccs.neu.edu/home/matthias/HtDP2e/

In the end, if you can make things that solve problems, that's what really matters. :) Consider a language like Clojure as another tool. There's no requirement that you use it.


https://github.com/pixie-lang/pixie could be worth a look.

That said, "add more type hints" hasn't generally been my experience of Clojure. If anything, it tends to be an indication that you've already gone a bit far down the path of "doing things the Java way".


If you read the forum threads on performance issues, what they generally come down to is type-hints & using Java types. The problem is that idiomatic clojure doesn't perform well (it may scale well but you throw away a bucket-load of performance by using it anyway). The way to get truly good performing Clojure is to write Java...

Pixie does look promising and is more my type of thing (coming from a low-level background) but I haven't managed to have time to look at it properly yet tho.


To really feel the difference you have to work on complex logic.

It's easy to be under illusion that you can create everything using a verbose language. At some point the complex system you work on just gets extremely hard to reason about.

For verbose languages you reach this point considerably faster.


This is super helpful. Reminds me of bropages: http://bropages.org/


Looks cool. Code indentation error/confusion at http://kimh.github.io/clojure-by-example/#future though.


Remind me of the little schemer. How about a "The little clojurist" book?


It reminds me to http://learnxinyminutes.com/docs/clojure/ but prettier.


http://www.4clojure.com/ should also be mentioned here. I had a lot of fun there.


This should be posted over to r/clojure


That's a great idea; just posted it over there and added it to the sidebar.


I love it!

The target audience is people with prior programming experience. It's important to know the target audience, either as a writer or reviewer.

The tutorial webpage is simple and effective with a gradual progression in concept difficulty.

I hope we have more things like this! Thanks!


Cool, thanks! Looks like a nice reference.


this is exactly how intro to programming language should be (for people who already know other languages)


Great execution, but the indentation is wonky at times, making it difficult to see the idea.


Good job Man! Bookmarked.


Very pleasant to read




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: