From the Clojure home page:![]()
Clojure is a dialect of Lisp, and shares with Lisp the code-as-data philosophy and a powerful macro system. Clojure is predominantly a functional programming language, and features a rich set of immutable, persistent data structures. When mutable state is needed, Clojure offers a software transactional memory system and reactive Agent system that ensure clean, correct, multithreaded designs.
I’ve had an interest in Clojure ever since I saw Craig Andera do a talk on the topic in D.C. (Craig also has a set of Clojure videos @ Pluralsight). It was just an intellectual fascination until clojure-clr appeared and things took a turn towards the possibly practical.
As a dialect of Lisp, Clojure embodies the spirit of the greatest single programming language ever designed, including the parentheses, prefix notation, and a simple, clutter-free syntax.
| Clojure | C# |
; Comparing 5 and 3+2 returns 0 (println (compare 5 (+ 3 2))) |
// Comparing 5 and 3+2 returns 0 Console.WriteLine(5.CompareTo(2 + 3)); |
Functions are first class citizens in Clojure, of course, so you can pass functions as parameters and return them as the result of other functions. There are closures, currying, and recursive looping. Fans of LINQ and functional programming with Func<> and Action<> on the CLR should know that you won’t be missing anything with Clojure, in fact, there is a whole new world to explore.
| Clojure | C# |
(take 2 (reverse
(filter (fn [s] (= \L (first s)))
["Minnesota", "Detroit", "London", "Las Vegas"] )))
|
var places = new string[] { "Minnesota", "Detroit", "London", "Las Vegas" } .Where(s => s.First() == 'L') .Reverse() .Take(2); |
Also, like any LISP, the compiler offers extensibility through macros. Program code is data you can evaluate or manipulate. However, the hallmark of Clojure is the inherent support for safe and simple concurrency. I plan on using Clojure in some data analysis work, and we'll explore interop and threading in a future post.
Comments
I think the primary differences (other than syntax) would be that Clojure is dynamic, offers transactional memory, and runs on both the CLR and the JVM.
Two reasons: syntactic consistency and variable arity.
Polish notation does not need parenthesis as long as every operator is of known arity. In lisps, the arity of many functions (including +) is variable, so there is no way to know, without the functional equivalent to parenthesis, to know when the arguments to a function are complete. So parenthesis are at least sometimes necessary.
Syntactic consistency ensures that they are always used and never optional. It makes it real easy to parse, and it isn't that hard to get used to them with a little exposure.