Getting Started With Clojure
jrheard.tumblr.com
jrheard.tumblr.com
Even if I like Ruby better than Java, it doesn't make Ruby a better Java because they are doing quite different things.
So I put off learning Clojure for about a year or so. However, I grew more and more weary of Java's obvious shortcomings, the inherent bureaucratic nature of the language and lack of modern programming features (such was the situation at the time at least, things are starting to look better for Java nowadays) and started to look to other languages. I tried Scala. It didn't work out. I still wanted to leverage my existing knowledge of JVM and the whole Java ecosystem, so I turned to Clojure again. Also, having spent perhaps too much time on HN, I really wanted to see what that fuss about Lisp was all about.
Anyway, what I found out was that you do not, in fact, need to be a genius developer to learn Clojure. Actually, Clojure was everything I hoped for. It's dead simple. The syntax is minimal compared to some other languages. You may have heard other people say that learning Lisp can be an enlightening experience. Yes, there definitely are some enlightening moments, but not in the sense that you need to spend years meditating on something to be able to understand it. Read a good book, there are plenty of those around now, watch some of Hickey's talks, and you'll get it.
To summarize, here's my message to anybody who is thinking of learning Clojure - don't get discouraged and give up on Clojure before even trying to learn it just because it's a Lisp. It may seem strange and perhaps a little frightening at first, but once you spend some time with it, you'll get amazed at how wonderfully simple it really is, and how powerful it is precisely because of this simplicity.
See? The magic was within you all along.
:)
I wonder if the causation is confused, here. That is, you do not need to be a top percentile programmer to understand or use Lisp. You are -- or become -- a top percentile programmer because you've learned Lisp.
I don't know if the relationship is as direct as all that. But I do think that if you learn and internalize some of the lessons of Lisp, it will expose you to new ways of thinking about programming as well a programming problems, and this is correlated with being a good programmer.
One particular example: the close relationship between code and data in Lisp pulls aside the curtain a bit on some concepts which are more obscured in languages like Java or C++.
For one, recursion. I 'got' it as far as the fact it's a function calling itself but it was only through digesting Lisp books, writing lisp and talking about Lisp that I finally got it. SICP helped further with recursive-iterative stuff too - it doesn't just need to call itself to be recursive.
Another is functional programming.
There are many more but the point is that I could have learned all these concepts, mentioned or not, in other languages but it was the simplicity of Lisp that I feel allowed me to truly understand them. I also feel if I dedicated more time into Lisp, I'd get much more than just a new language out of it.
One thing though, regarding this page, is that you don't need to install clojure with brew. Leiningen takes care of all that... clojure is just a jar that's included in your project, aka a dependency, and Leiningen manages that. This lets you tie a specific version of clojure to that project, which is handy for some legacy projects that aren't maintained anymore.
Also, if you drop the brew references, then this becomes OS agnostic. Just go to the leiningen page on github[1] and it'll get you started: osx, windows, linux.
I develop with clojure on my mac and I've not brewed anything related to clojure.
You do not "install" clojure. You depend on clojure just like you might log4j or joda-time
Also, I don't think anything would preclude non jvm hosted languages from doing something similar. I think it is a better solution than say virtualenv from python.
Considering a .jar is a zipped directory tree, and a virtualenv is a directory tree, would you be happy if we zipped up virtualenvs and called them .par or something?
I'm not sure what "language as library" will mean if you are not installing a VM or interpreter such as the JVM.
If you run a python program with virtualenv who decides weather to use python2.5 python2.7 or python3? Is it the author of the program? No, typically it is the user of the program who decides by symlinking /usr/bin/python
If you run a clojure program "lein run" who decides weather to use clojure1.3 clojure1.4 or clojure1.5. It is the author of the clojure program who decides by specifying in the project.clj file.
What I am saying is, I really prefer what seems to be the idomatic way of running clojure programs. This is totally possible with any programming language, but other jvm languages seem want to emulate the /usr/bin/runtime strategy. For instance the idomatic way to run a groovy script is to point /usr/bin/groovy --> ~/groovy-2.0/bin/groovy
and
$>groovy myscript.groovy
edit: grammer
.par is already taken. See PAR, the Perl Archiving Toolkit, which attempts to replicate jar for Perl.
Maybe, just maybe, the fact that Clojure isn't exactly the only program on earth running on the JVM and that, hence, there's a probability p far from zero that the JVM is already installed on your system / on your users' systems!?
It's more of a plus if you already have a JVM in place.
This is what rlwrap is for. Call `rlwrap clj` instead of `clj`, and you get all that and more (C-r, for reverse incremental search, etc). Works with every other REPL that doesn't bother to re-implement read-line.
As of a week or so ago, I started using Emacs with Clojure & nrepl. Aside from the occasional teething problems (still not used to the Emacs paradigm), it's amazing. Merely having the REPL in a text-editor-like buffer is a big win, and there's a bunch more that I'm still incorporating into my workflow.
But rlwrap is still a very useful tool because it works with every REPL. It will always be there, for those first sessions when you start learning a new language, or when you just need to answer some question about a language you rarely use, or when you write your own interpreter and don't want to also write read-line or an Emacs inferior-foo-mode.
I also recommend the Value of Values video presentation: http://www.infoq.com/presentations/Value-Values. It will help you internalize Clojure's approach to data.
I really wish I could remember why I didn't experience nearly as much pain starting out as the author, but I'm glad that he took the trouble to put this together.
The one I did bite the bullet on and watch in full was his talk on “hammock-driven development”. I liked it, but couldn't help feeling it would have made a very nice blog post that I could've read in 5 to 10 minutes as opposed to watching a 30 minute video.
I second fogus' comment about the Joy of Clojure, as well. I started with Simple Made Easy and the Value of Values before I even jumped into Clojure, and the Joy of Clojure dovetails quite nicely with all of the above.
I've always wished, though, that all "getting started" guides would just provide a chef recipe or machine image with everything ready to go. Getting to know a language shouldn't require jumping through an hour of hoops and documentation to get it set up.
(Of course, the guide here is broader than simply getting your system set up.)
It doesn't get much easier than pulling down the master `lein` script (or `lein.bat` for Windows) with wget/curl and setting it up on your PATH as an executable. This is similar to rvm[2], nvm[3], perlbrew[4], et al.
You'll need to have Java installed before proceeding to the next step.
Once you've done that, you can run `lein repl` in your shell -- Leiningen will bootstrap itself when it's run for the first time, and when it's done you'll be presented with a Clojure REPL. Now you're ready to start exploring and learning:
http://clojure.github.com/clojure/
Also, please join the friendly community in #clojure on irc.freenode.net[5]. You'll find folks in there nearly 24/7 who are willing to answer questions you may have as you learn your way around. The discussion group[6] is also a great resource.
[1] http://leiningen.org/#install
[2] https://rvm.io/
[3] https://github.com/creationix/nvm
IRC (#clojure and #clojure-doc on Freenode) is good for coordinating with other contributors.
For those of you in the industry, why would I want to use Clojure? What would be a good project to try it on? A Web app? Why is it worth learning it?
From my _very_ short experience (I've started coding a simple game), here are my two cents:
- If your application is heavily dependent on state, which changes continuously and must be maintained during most of the execution time - like a game - it may not be a good fit. You'll waste a lot of working around the fact that each modification results on new objects. - If your application comprises mainly of short requests that may create some state that will most certainly be discarded shortly after - like a web application - then I think it's a good fit and you'll probably enjoy it better.
Once again, I've just got started with it, so take this with a grain of salt :)
I may try the blog/webapp idea with Clojure.
I find the majority of my time in writing stateful programs goes towards reasoning about safety, and having access to STM lets me write correct code with less thinking. Then I focus on optimizing the parts where performance is critical.
I have found that this rarely enters discussions regarding Clojure, although the STM is frequently lauded. GHC's STM also does not work with the IOMonad, which is clear because of the types, and is articulated in books such as such as Real World Haskell.
http://book.realworldhaskell.org/read/software-transactional...
Are people really getting benefits from transactions which do not involve I/O?
Agents are integrated with the STM - any dispatches made in a transaction
are held until it commits, and are discarded if it is retried or aborted. Unlike refs and atoms, it is perfectly safe to use agents to coordinate
I/O and perform other blocking operations. This makes them a vital
piece of any complete application that use refs and Clojure’s STM
to maintain program state over time. Further, thanks to their semantics,
agents are often an ideal construct for simplifying asynchronous
processing involving I/O even if refs are not involved at all.
Further: Agents are integrated into Clojure’s STM implementation such that
actions dispatched using send and send-off from within the scope
of a transaction will be held in reserve until that transaction
is successfully committed. This means that, even if a transaction
retries 100 times, a sent action is only dispatched once, and that
all of the actions sent during the course of a transaction’s
runtime will be queued at once after the transaction commits.The critical thing, as you observed, is to separate IO from retryable STM transactions with a barrier; e.g. by receiving data, doing an idempotent computation inside dosync or swap!, and then emitting results. Haskell has an advantage in that this separation is provable by the type system, whereas in Clojure you need to remember.
A contrived example:
(let [pizza (get-from-fridge)
meal (dosync
(alter eaten-foods conj pizza)
(deref eaten-foods))]
(tell-friend "So far I ate" meal))
where get-from-fridge and tell-friend are IO operations, and our list of eaten foods is mutated by pure functions.In practice I don't find this particularly limiting: dosync and swap! are almost always short operations for performance reasons anyway. Then you return a consistent snapshot of the updated state from dosync--where multiple pieces of state are involved, you can use vectors or maps along with destructuring bind. Sometimes it's a tad unwieldy, but typically much shorter than the equivalent mutex dance.
There are other aspects of Clojure's concurrency libraries, like agents, futures, and promises, which are useful in IO. Specifically, agents give you asynchronous serializability, futures give you asynchronous concurrency, and promises allow for synchronous handoff of delayed values. Those are quite useful when working with IO, though for heavy lifting you may be better off using explicit queues and worker pools from java.util.concurrent.
Sometimes I think of Clojure (as an imperative language) as the dual of Haskell's lazy evaluation model. Clojure uses futures, promises, and lazy sequences to provide explicit laziness, where Haskell uses the IO monad to provide explicit ordering. Both have an STM for serializable, atomic mutability between threads.
Of course, everyone there is doing FP in C++.
Over the past couple of years, I've learned Common Lisp by working through Conrad Barski's Land of Lisp[0] and dabbled in Haskell via Learn You A Haskell[1]. I had a great time learning both, but I found that Common Lisp had a decent number of warts (e.g. four different kinds of equality) that seemed to be primarily due to backwards-compatability concerns, and I had a really hard time getting up and running when trying to write a simple webapp in Haskell. In addition, I've gotten spoiled by how batteries-included Python (which I use at my day job) is; the library scene for both of those languages seemed lacking in comparison.
What I like about Clojure is that it gives me fast immutable data structures, has a really strong emphasis on functional programming, and has access to a really huge amount of useful libraries.
So - I've mainly been learning Clojure as a nice treat for myself; the amount of jobs that exist that employ programmers to code specifically in Clojure didn't even really occur to me as something worth thinking about. It's just really a lot of fun to program in. Also, with any luck, I'll be able to transfer any lessons I learn from Clojure to my daily work in Python.
(Haskell still has a very special place in my heart [I do frequently find myself wishing I had types], I'm not trying to dis Common Lisp nor Haskell, I'm just trying to honestly answer the question of why I thought it was worth learning Clojure).
When you say "has a huge amount of useful libraries" but then say that Python is "batteries included", which libraries in Clojure are particularly useful? Which ones did you wish it had?
2) I used those two phrases interchangeably - I consider both Clojure and Python as "batteries-included" languages. Case in point - before I was aware that Clojure Toolbox existed, I was able to google "clojure http request" and find several libraries that let me perform HTTP requests programmatically that I could include in my project.clj and start using right away. My memory's a little fuzzy, so apologies if this is completely wrong, but I don't recall having as easy a time doing that in e.g. Common Lisp or Haskell.
As far as which libraries in Clojure are particularly useful - Ring and Compojure are fantastic, and core.logic[0] is extremely interesting; I'll write a blog post showcasing core.logic (and using it for my first time ever) at some point. Midje is great for writing unit tests. I've only been using Clojure for a few months, so I can't point to too many others that have really been extremely useful for me, but I definitely recommend checking out the Clojure Toolbox[1] for a more thorough list of the main contenders.
[0] https://github.com/clojure/core.logic/wiki/A-Core.logic-Prim... [1] http://www.clojure-toolbox.com
Basically it makes it easy to convert projects without tearing down your infrastructure, ie, easy to convince your boss.
If you really think that "four different kinds of equality" in Common Lisp is a wart, then I recommend that you read "The Best of Intentions" (http://www.nhplace.com/kent/PS/EQUAL.html) by Kent Pitman. The article explains why that situation is quite intentional, and why it is very rational, and why it is in fact ill-advised to expect a single meaning for "equal" ... or, in fact, other "obvious" concepts like "copy" ... to be sufficient.
That article was one of the many over the years that helped me refine the way I think about programming and programming languages.
If you want to start your own venture, using a powerful language like Clojure might give you an edge.
http://www.paulgraham.com/avg.html
Learning a powerful, less main stream language like Clojure can also signal to smart, innovative software companies you might be the kind of person they should hire.
# make sure you have java/open-jdk already
wget https://raw.github.com/technomancy/leiningen/preview/bin/lein && chmod +x lein && ./lein replI also want to point out to those who are using Windows: Yeah, you could, but this is not a good idea. Leiningen 2 is not available for Windows, but you can still get quite a bit done. At some point, you just have to bite the bullet and install a VM with Linux to really dive into it.
Light Table has a windows client; Eclipse with the counterclockwise plugin (a leiningen/clojure plugin) runs great on windows; running from the command prompt works great on windows.
I agree though, that a "Learn Clojure The Hard Way" a la Shaw would be nice.
I'm not a huge fan of using a bunch of IDEs and just use Emacs. After a year of fighting with Windows, I got fed up with it and installed Linux with a VM and now everything works like a dream.
EDIT TO ADD: I would love to do a project like Learn Clojure the Hard Way, but I'm simply not confident in my abilities to do it correctly. I've written some pretty significant programs in Clojure (see my profile), but I wouldn't be able to solve but a few Project Eulers with it. I'm simply too new at programming in general.
I just used the batch file from the leiningen github to get up and running on windows.
Someone else brought up the point that lein needs wget or curl, and that isn't something that is installed by default on windows. I happened to already have them, so I never thought much about it.
GNU has a version of wget and maybe curl too for win32. And there is always cygwin if you like.
https://github.com/technomancy/leiningen http://gnuwin32.sourceforge.net/packages/wget.htm
I'm pretty much a novice when it comes to software in general, but I dip my toes in a lot of different languages. I don't think that would be a problem for LCtHW though... I mean, it could be a collaborative effort as a github page or wherever.
Get the framework in place, start with the basics, let the experts fill in the advanced stuff.
One of the things you can do when learning something new is to hop onto IRC and join a channel related to the topic. I almost always have got a good overview of things just by asking around what I am supposed to know.
I've read a page[1] listing differences between Clojure and other LISPs, but I'm not sure that I fully understand the implications of these differences.
this video by Chas Emerick (co-author of clojure programming) also gives a good introduction to start with clojure, especially for people who uses eclipse.
(:headers resp)
This construction is confusing - it breaks environmental model (scoping) and general evaluation rule of Lisps - is :headers a global symbol? a part of foo namespace? Is it macros? (resp :headers)
On the other hand, this form is perfectly consistent - I'm sending to some closure which is bound in a global or other environment a constant message.The assumption that the reader function implicitly transforms first form to second is of no good, because it is not obvious and breaks intuition about environments and violates principle of less astonishment.
That thing (:headers resp) returned - what language is it?)
It follows Clojure's evaluation rules just fine: it's an object that implements the IFn interface.
> On the other hand, this form is perfectly consistent - I'm sending to some closure which is bound in a global or other environment a constant message.
resp isn't a closure, it's a map, which is also an object that implements IFn.
(:keyword m)
calls in turn (get m :keyword)
That's just a basic feature of the language. No macros involved.It seems to me that a function must be defined somewhere before one could call it.)
The keyword is a function i.e. (in Java terms) it implements the IFn interface.
The effect of that function is the same as calling the get function on a map using the keyword as the argument.
If it is a function, where it is defined and when?
That's why I'm arguing that this form is confusing, and that transformation is more correct notion, at least if people are insisting to call it Lisp.)
It is also a function though, and can be used in the function position of a function application just like any other function.
Keywords and all their functionality are defined as a primitive in Clojure, i.e. in the Java source code for the language.
It's typically one of the first things people learn when they pick up Clojure, and is used as an idiomatic way to access maps whose keys are keywords. I would argue that is is not confusing and that it is totally consistent - all you were missing is one fact: keywords are functions.
The logic is that this object could be called as a function and at the same time always evaluated to itself?
That means whenever you call it you always getting it back - this is behavior of a constant. But if you could call it with an argument, you will get back some value, different from whatever it is?
As long as maps are immutable, it will behave as a function - return the same value for the same argument.
OK, but, please, don't tell me that this isn't confusing.)
No! You're confusing functions-as-callable-things and functions-as-values. The phrase "a constant" does not generally imply anything about a thing's behavior when called. It just means something whose value will never change. A self-evaluating constant is a constant that circularly evaluates to itself — nothing else can have that value without referring to the constant. But neither of these things have to do with calling anything; they're just about taking values.
A constant can certainly refer to a function that returns something other than that constant. For example, in Ruby: `Example = lambda { 1 }`. If you just evaluate "Example", you will get a Proc value, but if you call Example, you will get the Fixnum 1.
In most languages that have them, you cannot call a self-evaluating constant. It won't return itself — it's just not a callable thing. In Clojure, keywords are self-evaluating constants that have the behavior of looking themselves up as a key in the argument when called. They serve the purpose of self-evaluating constants exactly the same as in other languages, but they also have the handy property of doing map lookups.
Call it "callable" if you prefer. Much the same way as in C++ objects that define operator() are callable; only cleaner.
As I understand it, the roles which things like lists and functions play in a traditional lisp are replaced in Clojure by abstract datatypes corresponding to Java interfaces. Which on one hand is kinda neat because the core lisp datatypes aren't tied to specific concrete implementations and other datatypes (including user-defined ones) can participate in the same abstractions.
On the other hand it means the semantics become quite tied up in underlying JVM-related details and don't seem as clean/elegant as (say) Scheme.
On the other hand it means the semantics
become quite tied up in underlying JVM-related
details and don't seem as clean/elegant as (say)
Scheme.
That's not very true. Instead, Clojure is defined in terms of specific abstractions. Whether those take the form of interfaces or protocols is irrelevant because it's the abstractions that count. If it were tied strictly to JVM-related details then ClojureScript would have been much harder to implement than it was.The elegance of Scheme is subjective.
I recall some debate about changing this so you can implement them using the native abstraction facilities in clojure (protocols), at which point I'd probably withdraw my point.
But yeah elegance is subjective. I use Clojure and broadly like it, JVM interop is really useful, but the lack of a crisp separation between clojure semantics and JVM semantics does still irk the purist in me a bit.
I guess I'd see Clojure and ClojureScript not as one language on two host platforms, but as one JVM language and another similar but not really source-compatible language on another platform which is influenced by it. Part of the philosophy seems to be to make pragmatic decisions which blur the boundary with the host platform, rather than try to abstract over the differences in APIs and runtime semantics.
>> I recall some debate about changing this so you can implement them using the native abstraction facilities in clojure (protocols)
You mean records (defrecord): http://clojure.org/datatypes
Dunno how feasible this is, but if a language is going to define its own abstraction features (here, protocols) on top of the underlying platform, it would seem cleaner to eat ones own dogfood in using these abstraction facilities for the core abstractions which the language and its core library are based on.