
The Beauty of Clojure - erikcw
http://owenrh.me.uk/blog/2015/08/24/
======
nnq
I don't get it why Clojure and other Lisp tutorials throw things like this in
face of beginners:

    
    
        (reduce + (map (comp inc inc) (range 10)))
    

instead of just using things like the "->" macro to make the damn thing just
as in any other language:

    
    
        (-> (range 10)
            (map #(+ % 2))
            (sum))
    

...it's as if _they purposely try to scare people away from Lisp!_ Some kind
of smug superiority makes them wanna make sure no "lesser mortals" want to
touch their beloved language. (The added benefit would be that later you can
"blow their minds" but showing them how to _write "->" themselves_ and
instantly introduce them to the power of macros!)

This is almost close to showing a code snippet like this to someone trying to
learn Haskell:

    
    
        fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
    

(it only prints the powers of 2, but it was enough to scare some people into
calling Haskell “the Taliban version of ML”...
[http://www.theregister.co.uk/Print/2012/12/21/financial_soft...](http://www.theregister.co.uk/Print/2012/12/21/financial_software_disasters/))

...really, people, stop scaring learners away!

~~~
VladimirGolovin
I'm new to Clojure and I'm trying to parse this line:

    
    
      (reduce + (map (comp inc inc) (range 10)))
    

Is the following a correct Haskell equivalent?

    
    
      foldr1 (+) (map (succ.succ) [1..10])

~~~
vzcx
Mostly, but I'm pretty sure Clojure's range gives the integers from 0 to 9.

------
numlocked
This is very similar to my experience. There's definitely some friction
getting started; the odd using/require macros for importing (which switched
sometime in the last 2 years, which means a lot of out-of-date SO answers);
the fact that most docs recommend using emacs which, if you aren't already a
user, is not going to be easy to deal with; the parens.

But it's amazing. I do really miss types, but found that unit tests +
Schema[0] serves my needs; they provide some type-ish enforcement, and do a
terrific job documenting my code so that when I return to it months later, I
have some idea of what's in all these map structures.

Another unsung feature is that emacs + paredit + s-exprs + repl means the
actual mechanics of writing Clojure is wildly better than any other dev
environment. The ability to operate confidently and consistently on semantic
units of code vs. text is really amazing and I immediately miss it when I
switch back to JS or Python. I'm sure other Clojurists felt they had already
experienced something like FB's Prune when it was discussed here a few days
ago.

Not to mention learning a Lisp really does increase your understanding of
what's possible. I've seen others recommend holding off on playing with macros
until you've become quite familiar with the language, but I couldn't disagree
more. Play with them right away! I have perhaps ~200 hours of Clojure under my
belt -- barely anything -- but I've hacked together a few useful macros.
Though I barely understand how they work when revisiting them, it definitely
increased my understanding of what's possible, and what's missing, in other
languages.

So yeah...learn some Clojure. Just do it.

[0] [https://github.com/Prismatic/schema](https://github.com/Prismatic/schema)

~~~
Mikera
Note: you don't need to commit to Emacs to get the productivity benefits of
Clojure.

Eclipse with the Counterclockwise plugin (and I believe IntelliJ with Cursive
too) also give you comprehensive REPL, s-expr manipulation and paredit
features.

~~~
ane
The benefit of CIDER (the Clojure Emacs development environment) is that it
now has a s-expr based debugger, whereas Cursive's debugger is still call
stack based. So you can traverse the AST like in any other Lisp debugger and
evaluate and manipulate s-exprs as you go.

------
_pmf_
I've asked on StackOverflow, got shut down violenty, so I try to ask here: how
do developers in large(-ish) projects deal with the lack of tool assisted
refactoring? (Renaming a field in Java, I am 100% sure that every call site is
found, changed or otherwise the codebase does not compile. The catch-all
clause of dynamically typed language users seems to be that the test suite
should catch everything, but looking at most projects, it's outstanding to
even see 40% test coverage.)

~~~
jarcane
I've never really needed it in Clojure. The code is that much more expressive
that overall LoC is dramatically reduced (thus more easily viewed "in the
whole"), and following a proper functional approach means good functions
should be largely interchangeable and not dependent on any global state. So on
the rare occasion I need to move something around, it's just meant a quick
copy and paste and tweaking a few references.

Yes, Clojure is dynamically typed, but I think you're missing the gains you
get from FP and expressiveness in terms of reducing labor.

~~~
eurekin
I was trying to find time for Clojure, but I had always had doubts - exactly
as the grandparent commenter...

He touched upon what I think is essential. The biggest things to lose by
giving up Java is the tooling. Using the IDE I have many possibilities to
learn about code, without ever needing to run it. For example by using find
usages/implementations. The types on methods often give out hints about the
big picture. Like, if a method passes a JAXB context, than I know I'm in the
infrastructure layer. If I'm looking for a business rule "how is the price
calculated", I can very quickly cut off a large portion of code which does not
do it. After few iterations, it's almost certain I will get to the relevant
code part.

Then I typically launch an application and put a breakpoint, to test my
assumptions. After that, I have a lot of confidence about how the application
behaves in that spot, even If I saw it for the first time.

If anybody asks me "Tell me if we can extend the functionality of calculating
user score to include expert rating", I can provide a good effort
approximation, even in a never seen before application. I just know, that
given the tooling, I can filter out unrelated code parts and concentrate only
on the relevant one.

The above concerns only code comprehension of a large project. The tooling
does give you also power to do macro level restructuring, like breaking a
large monolith into smaller modules. The compile time errors are like a high
accuracy automatically generated todo-list.

Since it takes so little effort to make large changes, you gain the ability to
do it multiple times and refine. If I broke something into two modules and a
dependency cycle came up, I see it right away and can do everything again, a
little bit better with the extra knowledge I got.

I have never seen anybody doing the same in Ruby, maybe because I've been
working only about two years commercially in it, but a lot of times I've seen
something quite opposite: introducing more hacks decreasing code quality, just
to work around some conceptual error. While working in Java, I have seen a lot
of situations like "we'll doing a hack here and the real solution will come
with the next big release" and really the solution does come.

High level changes typically break a lot. With tooling, you gain confidence
you can fix them, without introducing a lot of regression bugs. In Ruby, I saw
the people just give up and leave monkey patches around. Then they just leave
the project for the next unfortunate programmer.

So, back to the topic. You say that the change name refactoring is very simple
in Clojure, because the impact of change is local to the method. My question
is: How does Clojure tooling aid You in changing a place with a global impact?
Like, changing the argument list of a very often called method (e.g. the
method to serialize a structure to string to require the caller to provide an
explicit encoding)? Can You, right after doing the change, quickly estimate
how much work is there to fix all affected places? Do You have confidence that
the list you provide is complete and doesn't miss anything critical? How
certain can you be without running the code, only analyzing?

~~~
jarcane
1) That's up to the tests, just as in any language.

2) Some of the changes you describe are no less trivial to experiment with in
an environment with a REPL. I routinely trial changes to small functions
simply by running them in the REPL as discrete units before attempting to re-
start an entire server project.

3) Good FP strategy rarely means dealing with _anything_ with a global impact.
About the only exception is client-side ClojureScript, where keeping a single
"state" atom is largely idiomatic, and even then, actually using it is a last
resort action reserved for things like routing and user session, preferring
instead local state unique only to a single file for anything else that
requires it.

I think this is a case where you need to experience just how big the
difference is between an expressive FP approach and something like Java is to
really understand why it's not a problem, and indeed, amounts to something
like a category error.

When a Java programmer asks me about refactoring Clojure features, I can't
help but think about stuff like how the entire messaging system for the app I
worked on over the summer fits on maybe 3 or 4 printed pages of code and only
took a week and a half to complete, compared to say, EnterpriseGradeFizzBuzz
... The tools you describe sometimes don't exist, it's true, but that's
because no one needs them. They exist to automate tedium and complexity that
is largely idiomatic to Java and other similar OOP languages, but not
expected, desired, or necessary in other paradigms of programming.

I know it's hard to believe, but there are other ways of doing things. We do
alright, I promise.

~~~
eurekin
Thank You for the answer!

After I reread my own comment I realized it sounded much more harsh than I
wanted. Good you were not put off by the tone. Sorry for that.

I have to admit that my biggest pet peeve with working in Java projects are
those high impact changes. I try as much as I can to propose "extending"
changes, but working in a team means someone certainly at some point will
propose "changing" how something works, without ever realizing all the
consequences.

If by using Clojure you get the same benefits of what the best OO practices
can give, than I'm willing to give it a try.

I do remember a presentation about working on immutable snapshots of reality,
it was something along the lines "How do you normally check if a runner had
both feet above the ground?". The example there was, that a typical imperative
programmer just checks the first foot and then the other. Naturally, the
second check happens some time after the first one. The selling point was
that, in Clojure, that you operate on a immutable snapshot of a runner in
time, so the feet are by default in the same point in time.

So, I'm liberated from thinking about a whole category of potential errors. I
liked it a lot.

There are some other categories of potential errors as well. I mentioned them
in my comment and you cleared that up for me.

Still I have another doubt, regarding a typical code reuse scenario. A simple
example follows.

Let's say a programmer needs to ask the user for input. He writes a code,
which pops up a user interface dialog and wires up an action to the buttons
callback. All is fine. As the time passes, there is a need to provide more
questions to the user. The dialog code grows. Someone files a bug, that, in a
multi-monitor setup, the dialog shows up always on the wrong screen. The bugs
get fixed. More dialogs are introduced. Another project starts up and wants to
use the nice UI code. We designate it for a separate library. The first
project must isolate and make everything generic. The requirement is that both
projects must work on top of that library and the first one cannot loose any
functionality.

This is where the tooling excels most. You just make the duplicated UI code
look the same and use the "extract method" refactoring. The IDE tells you "I
just found 5 duplicates, should I replace them all?". You answer yes. The IDE
even tells you if there are any potential side effects. If there are none, you
proceed. Then you use "use interface instead of method call" refactoring. In
that way you can nicely extract contract between the client code from the
library code. You move the stuff around, so that the library code lands in
other project.

Then, You can just wire the library as a dependency in the Project B. It
happens, that some needed functionality is not exposed. So you change the
library and immediately see the impact on the A Project.

The case here is: you do not have to understand the A Project as a whole,
since the tooling takes care of so much of the static dependencies. You just
pull out the fun stuff and patch out the wounds. It does not require a lot of
skill or knowledge, so a new project member can also be designated with a such
task - not only the knowledgeable rock-star programmers that have the whole
project in their head.

If you can assure me that in Clojure you can do the same in a safe manner than
I'm all in. :) I'd appreciate any articles or stories explaining such
scenarios in detail.

~~~
huahaiy
In Clojure, one doesn't need to rely on tooling to do refactoring, because
things are isolated, loosely-coupled to begin with. There isn't much
"unintended side effects" when one change Clojure code, because Clojure code
consists of a bunch of functions working on immutable data structures.

The feel of programming in Clojure is very very different from what you are
describing in a language such as Java. I have programmed Java since 1997, ever
since I switched to Clojure, all those pains and fears of changing code has
evaporated. I am not afraid of changing things in Clojure at all, because I
know the effects of my changes are local.

Of course, Clojure toolings do include some convenient features such as
"extract function", "rename symbol", etc, but these are just some niceties
that save some typing and editing. They are not indispensable like those in
Java.

~~~
eurekin
Ok, so there are a lot less unintended side effects. I got that.

What about the intended ones - how do You approach them? Let's say You've
written a ClojureScript webapp using the Angular framework and you need to
migrate it to V2. AFAIK there were some breaking/conceptual changes which
force significant rework. How do You make sure that after changing it
everything works - even the most obscure option that only one user uses (as in
the notorious example of Search Keyboard Shortcut in Outlook by Bill Gates)?

~~~
grayrest
> You've written a ClojureScript webapp using the Angular framework

I know this is an example but Angular is terrible with Clojurescript. Clojure
has an opinionated idea of how state should change over time and that opinion
does not include two-way bound attributes. The reason the cljs community is
virtually all React is because dom diffing makes the UI effectively a
projection from state and that is epochal-time compatible.

> How do You make sure that after changing it everything works - even the most
> obscure option that only one user uses?

Depends how your app is designed. In the general case where, say, you're doing
the equivalent replacing Angular with Ember you just have to do it and lean on
tests/QA. I have just recently finished such a refactor and it's about as fun
as you're implying.

With the refactor, I have a better plan going forward! We're now on the re-
frame model. All state is now in the global atom (instead of mostly being in
the atom but some being component-local), dataflow is unidirectional, and
we're capturing all non-determinant actions as event params. Together, it
means serializing the state atom and a sequence of events allows playback on
the changed code. At least in theory. I wound up having to ship rewrite
delayed features and haven't taken the time to build recording/playback
support.

------
escherize
S-expressions have changed the way I think, and it's really great. With
paredit (or some other structural editor) and hiccup[1] I can make html so
quickly out of pure functions that it's truly a joy. Using Clojure's
datastructures, along with all the functions made to alter those
datastructures gives such an immense feeling of power.

[1] [http://hiccup.space](http://hiccup.space)

------
bad_user
As disclaimer, I've been a Scala zealot for the last 3 years. On Clojure vs
Scala, usually comparisons are kind of unfair I think. As somebody interested
in FP, I tried Clojure first. And FP being all about immutable data-
structures, pure functions operating on immutable data-structures and dealing
with side-effects explicitly by means of abstractions such as the I/O Monad, I
expected to see that in Clojure, seeing how people describe it as being very
FP.

And it was like a big WTF for me seeing how for example everything in Clojure
is a Var that can be changed. And eventually I got it, I mean Clojure is a
LISP and it's meant to be compiled by a REPL and the unit of compilation is
not a file and this is in LISP's tradition and so on and so forth. But it's
still a WTF given its usual characterization. Even in Java classes are
completely immutable (until you start manipulating bytecode of course) and
you've got "final" declarations. You have no "final" in Clojure. And this is
actually a pity because it (probably) means that those persistent data-
structures can't be implemented in Clojure, as "final" on top of the JVM comes
with a pretty cool contract in the Java Memory Model that you need. And then
instead of Scala's implicit parameters, that are actually very explicit and
type-checked by the compiler, in Clojure you have package-wide vars or refs
that people manipulate as a poor man's dependency injection mechanism. And
state changes are usually done by mutating atoms. Well that's cool, in Scala
people also do that, but in Scala you also have a mature implementation of the
I/O monad and monad transformers if you want it, or various FRP libraries. And
I'm sure that Clojure has plenty of libraries, but overall I feel that in
Scala the ecosystem of design patterns _borrowed-from-Haskell_ is more mature.

Scala provides mutable variants of its data-structures in the standard
library. But that's not extra rope to hang yourself, because in Clojure the
use cases still exist and people end up using Java's mutable data-structures
instead. In Scala the blend of OOP and FP can sound overwhelming, but it's
actually the healthiest blend of FP + OOP to ever come up in a programming
language. And in Clojure, just because you can't declare a class, that doesn't
mean that OOP doesn't exist. It does and the blend is not healthy. This is why
"reify" and "proxy" exist and are used quite frequently. And things like
clojure.lang.ISeq are a Java OOP interface and not a protocol. Basically Scala
is trying to make the best of OOP, whereas Clojure considers it a necessary
evil of the host platform that it can't get rid of. Pick your poison.

~~~
pjmlp
> In Scala the blend of OOP and FP can sound overwhelming, but it's actually
> the healthiest blend of FP + OOP to ever come up in a programming language.

Have you tried OCaml or F#?

~~~
whateveracct
Scala is definitely a better blend of FP and OOP than either of those
languages. It's also a heavier FP language that either of those.

~~~
pjmlp
I fail to see how.

~~~
justthistime_
Scala is more functional because it encourages immutability more strongly and
allows better abstractions like typeclasses, higher-kinded types while being
roughly even on the modularity front with OCaml (there are a few things easier
done in OCaml and a few things easier done in Scala) and beating the shit out
of F#.

Not having a separate module and object system is another plus when compared
to OCaml.

It unifies OO and FP better than OCaml and F#, because OO implemented in OCaml
and F# feels like the designers tried to make a point about how much they
dislike OO. What's the first thing OCaml/F# devs tell others about OO in their
langauge? To avoid it.

~~~
tel
They tell people to avoid the things _called_ objects in OCaml which
essentially are just row-typed dynamic records and an inheritance system.
Really it's the inheritance system people are taught to avoid... Same as
anyone in OO is being taught now.

OTOH OCaml, as an ML, inherits an _outstanding_ module story which is really
the core of OO anyway. I'd happily say OCaml is a better OO language than
Scala for that reason.

~~~
justthistime_
The module story is pretty comparable and many things can be translated
directly between OCaml's module system and Scala's.

With the module being roughly equal, and while objects suck in OCaml, but
don't suck in Scala, I'm kind of surprised by your judgment.

~~~
tel
The module system _is_ the object system fwiw. The things OCaml calls objects
are just dynamic row-typed beasties which is why nobody recommends them
(except to use as phantom parameters to get your own row typing).

------
dantiberian
> I can refactor a huge codebase in my IDE. Good luck trying that with
> Clojure.

Cursive Clojure, a plugin for IntelliJ has excellent refactoring support,
especially considering how dynamic Clojure is. If you've come from a Java
background, this gives you a lot of the refactoring and 'Where Used'
functionality that you might be used to.

~~~
lewisl9029
Yep, Cursive is definitely quite impressive.

Here's a very informative intro by Cursive's developer, complete with some
very compelling demos:

[https://www.youtube.com/watch?v=vt1y2FbWQMg](https://www.youtube.com/watch?v=vt1y2FbWQMg)

------
sanatgersappa
Great post.

Most discussions on lispy languages focus on the syntax. The unsaid assumption
is that the only diff between a lisp and a non-lisp is the syntax. However,
using lisp actually makes you think differently about programming. It is that
which for me personally, is the selling point of a lisp. The syntax itself is
merely expression, and is honestly simpler to grok than most other languages
thanks to its consistency.

------
pron
This post focuses on Clojure as a very pragmatic Lisp, but that, while great
in itself, is not what makes Clojure so interesting. Clojure has proposed an
interesting solution to the shared mutable state problem without trying to
reduce it as much as possible like Erlang and without being pure functional --
and thus changing the whole concept of state and effects -- like Haskell
(Clojure is imperative-functional). Clojure's solution is that all shared
mutable state be transactional (or atomic, which is a special case of
transactional). AFAIK, this is the first language to do that (again, without
going down the pure-functional path). An imperative language that doesn't
restrict global mutable state, but makes it transactional is a very
interesting case study.

------
edgyswingset
I wonder why the author left the thread-first and thread-last macros as a
footnote.

This:

    
    
        (reduce + (map (comp inc inc) (range 10)))
    

And this:

    
    
        (->>
           (range 10)
           (map (comp inc inc))
           (reduce +))
    

Are totally different from a readability standpoint. Yeah, there's some
initial syntax to get used to, but in the long run I've noticed it to be the
difference between immediately understanding what some code is doing and
having my eyes glaze over.

------
bonobo3000
For the OP - i've recently been programming in Scala, mostly spark jobs,
nothing too complex, but damn its beautiful. I love how expressive the
language is (certainly it can also be very complicated in large codebases, as
you use more features, but I haven't encountered that yet). Heck just the
simple 'scala' repl + JVM interop makes developing Java code so much easier.
You seem to have tried Scala too - i'm wondering what you think of Clojure vs.
Scala and what made you switch?

~~~
sklogic
Scala got no macros. Which makes it infinitely less powerful than _any_
language with macros, including even something like Clojure.

~~~
bonobo3000
Similarly, Clojure got no types. Which makes it infinitely less runtime-safe
then ___any_ __language with types. Takes a more nuanced argument.

~~~
sklogic
For a language with macros it does not matter at all. You can add _any_ type
system you like on top of it. Metalanguages are infinitely flexible.

~~~
justthistime_
The strength of a type system is that there is one. If everyone uses his/her
own self-made pet of a typesystem most of the benefits are gone as soon as you
are more than a one-man-hobbyist project.

Probably explains why most Lisps consist of one-man-hobbyist projects, though.

~~~
sklogic
> The strength of a type system is that there is one.

I do not agree. There is no single type system that would fit all the possible
use cases.

> Probably explains why most Lisps consist of one-man-hobbyist projects,
> though.

No, it does not.

~~~
justthistime_
Type systems are by-definition only a conservative approximation of all
programs.

The good thing is that 99.999999999999% of all programs never need to be
written, and there are plenty of type systems which deal well with the last
0.00000000001.

> No, it does not.

Ok, that leaves the failure of Lisp outside of hobbyist mom's basements a
mystery.

~~~
sklogic
> Type systems are by-definition only a conservative approximation of all
> programs.

This is where I lost a track of your arguments.

> Ok, that leaves the failure of Lisp outside of hobbyist mom's basements a
> mystery.

Lisp did not fail. It's in pretty much all the mainstream languages now.

~~~
justthistime_
> This is where I lost a track of your arguments.

Then maybe you should maybe spend some time studying these topics instead of
acting up on HN.

> Lisp did not fail. It's in pretty much all the mainstream languages now.

This is where I lost the last doubts about the reality and your lack of
closeness with it.

~~~
sklogic
> Then maybe you should maybe spend some time studying these topics instead of
> acting up on HN.

Chances are, I implemented more varieties of type systems than you can name.

> This is where I lost the last doubts about the reality and your lack of
> closeness with it.

Scala fanboys are much more detached from the reality. The reality rejected
bondage&discipline languages long ago.

~~~
justthistime_
You continue to amuse me.

~~~
sklogic
You did not answer, fanboy. Does Scala already allow to use macro in the same
compilation unit it was defined?

~~~
dang
> You did not answer, fanboy

We ban accounts that do this repeatedly. On HN, please post civilly and
substantively, or not at all.

------
rjeli

      (reduce + (map (comp inc inc) (range 10)))
    

is not analogous to (_ + 2). The more similar and idiomatic code is:

    
    
      (reduce + (map #(+ % 2) (range 10)))

------
jdeisenberg
The first example could also be written as:

    
    
        (reduce + (map #(+ % 2) (range 10)))
    

which looks more like the Scala example, or, perhaps more readable, in the
long form:

    
    
        (reduce + (map (fn [x] (+ x 2)) (range 10)))

------
mseepgood
Why is reading from left to right counter-intuitive? Don't we read f(x, y)
from left to right as well? (f x y) has the same order, even the same amount
of parentheses.

~~~
daxfohl
(< x y) is the main one I have trouble with. The alligator is eating them
both!

------
huahaiy
For this code,

(reduce + (map (comp inc inc) (range 10)))

Clojure people would normally use thread macro, like so:

(->> (range 10) (map #(+ % 2)) (reduce +))

This would be similar to the Scala version in term of order.

~~~
fnordsensei
This reminds me that there really should be a reader macro for "partial" in
Clojure.

------
kazinator
> _The use of s-expressions and their resulting prefix notation is in many
> respects the secret sauce of Clojure. However, it requires you to read
> right-to-left3 and inside-out. This is counterintuitive to most of us, and
> takes some getting over. It is a very real barrier to entry for Lisps._

Author still doesn't get it. Lisp must, in fact, be read from the outside in,
left to right --- in the same obvious direction in which it is evaluated. It
is not very different from a nested f(x, y, ...) notation, except that the
commas are gone, and the f ( exchange position to the ( f arrangement.

As a trivial example of why outside-in is wrong, is that if you follow that
order, you might believe that (b c) is a function call in (defclass a () (b
c)). The most important fact is that this is a class definition (in ANSI
Common Lisp). The leftmost symbol in the outermost form, defclass, is the what
McCarthy called the "main connective". It determines the entire meaning of the
interior of the form and all of its subforms, so it behooves us to visit that
first. When we recognize that, we then know that (b c) are slots, and not
operator b applied to argument c.

The right-to-left part is completely bizarre. Why, as a matter of course,
would you read the arguments of a form before the main connective symbol? If
that, you want, languages for you, there are: Forth, PostScript.

~~~
owen4d
Ha, yeah, maybe. I guess what I meant is this, say you have some OO/Scala-like
code like this:

mydata.doA(blah).doB().doC(blah2).etc()

You can read it left-to-right: I've got some data, I do something to it, I
then do something else to that result, etc. Maybe it's just that I've been
using Java, and the like, for years but this feels simpler to me than
s-expressions. At least initially.

With s-expressions I get something like (ignoring threading macros):

(etc (doC blah2 (doB (doA blah mydata))))

So when reading, from a data perspective, you kind of read outwards from the
inner s-expression (which seems right-to-left to me). Or keep a kind of mental
stack, as you read inwards (left-to-right). No?

------
skimpycompiler
As much as I like Clojure the lack of static typing always made refactoring a
pain. The lack of it makes this a beauty I just can't appreciate and see.

------
diego
(comp inc inc) is weird. You'd normally use #(+ 2 %) or (partial + 2) instead.

~~~
owen4d
Yeah, definitely. My bad. It's definitely not idiomatic.

I think was trying to avoid using the anonymous fn syntax, as I thought that
was be more off-putting, and partial hadn't occurred to me at the time. In the
end, I think I just confused the issue.

In retrospect, I should probably have used a totally different example, and
avoided map and reduce as they are FP idioms. Live and learn, as they say.

------
erichmond
My couple of comments:

\- Great write up, very approachable for who may be on the fence about toying
clojure.

\- Re: Enterprise, while our enterprise footprint isn't ubiquitous yet, there
are a couple of big name companies using clojure pretty heavily. Amazon,
Walmart and Two Sigma amongst them. Also, because clojure sits on the JVM, we
have a good interop story with legacy java codebases.

\- Re: Refactoring, you should checkout intellij + cursive clojure, it's made
refactoring codebases much easier for myself.

~~~
owen4d
Thanks.

Re: Enterprise, I've seen a presentation about some of the work going on at
Walmart. Would be great to hear more 'stories from the trenches' from larger
scale developments. It would really help sell the language.

Re: Refactoring, yeah, I'm totally busted on that one, my wording was way too
strong as I haven't tried either Cursive or clj-refactor. Plus in a way, it's
an apples and pears comparison, between OO and FP refactoring.

------
pjmlp
I would like to try to use Clojure for mobile development.

Together with ClojureCLR, RoboVM and reader conditionals it would be a good
mix, without having to deal with FFI headaches.

But currently it is too slow on Android and I don't know how well ClojureCLR,
if at all, runs as Universal Windows App.

~~~
hellofunk
For mobile a lot of folks are now using Clojurescript. There have been several
highly rated discussions on here about the breakthroughs in the Clojurescript
community for getting it to operate very quickly on mobile devices.

~~~
pjmlp
Thanks, but that approach is not something I would enjoy.

I try to stay away from the JavaScript universe unless I have a customer
requesting a webdev project.

For me mobile dev means only native code and not web widgets.

~~~
hellofunk
I can understand, but JS is not what it used to be. Things like React, OSX
JavaScriptCore, Qt's native JS engine (which also allows you to build native
apps for any desktop or mobile platform using Clojurescript), the use of
Clojurescript server-side with Node, the state of affairs in JS are changing
very rapidly, and Clojurescript is right there for leveraging all of it.

~~~
pjmlp
I do know JavaScript quite well, most of our customers require web
applications.

Using JavaScript related tooling outside work does not relate with fun, at
least not for me.

------
tragic
"FYI - there are better books to get started with [than the Joy of Clojure]."

FMI: what are they? :-)

~~~
emil0r
Programming Clojure 2nd ed, Clojure for the Brave and True. Probably others as
well :)

~~~
erichmond
+1 for clojure for the brave and true. Best overview book out there IMO.

------
crimsonalucard
Which is more beautiful, haskell or clojure? This is a subjective question, so
I'm hoping to read subjective and highly opinionated answers.

~~~
rtpg
well that first example in the article would be

    
    
        foldl (+) 0 (map (+2) [1..10])
    

or

    
    
        sum $ map (+2) [1..10]
    

So... make up your own mind.

As someone who has written only small chunks of lisp but at many different
points in life, I do find the whole parens game to be a bit disorienting, but
usually I can counter it by using newlines.

I would write something like

    
    
        (reduce + (map (comp inc inc) (range 10)))
    

as

    
    
        (reduce +
                (map (comp inc inc)
                     (range 10)))

~~~
zeekay
Ranges are inclusive, so:

    
    
      sum $ map (+2) [0..9]
    

Nitpick, but it confused me for a second.

------
infiniteseeker
Is there a good online course for a beginning programmer who wants to learn
Clojure? If not, a good book with exercises?

~~~
owen4d
Clojure Koans, is similar to 4clojure, and also worth a look>
[http://clojurekoans.com/](http://clojurekoans.com/)

Bookwise, I thought the following were pretty good: 'Clojure in Action' by
Amit Rathore and 'Clojure Programming' by Chas Emerick are both solid intro
Clojure books. 'Web Development with Clojure' by Dmitri Sotnikov is also a
great book, which obviously comes with more of a web-slant.

And I'd give a second thumbs up for 'Clojure for the Brave and True'.

------
pixie_
The line below looks a lot more readable than the closure version.

Enumerable.Range(1, 10).Select(i => i + 2).Sum()

~~~
Scarblac
And I prefer

    
    
        sum(i + 2 for i in range(1, 10))
    

for readability. But we shouldn't judge languages on this sort of thing --
because then why don't we just write sum(range(3, 12)), or 63?

~~~
pixie_
In both those cases you have to read it backwards to see what it does.

------
zubairq
Not, entirely true, there are some Clojure Frameworks like this one
[http://coils.cc/coils/a-framework.html](http://coils.cc/coils/a-framework.html)

------
cranium
Perfect description of the average Enterprise codebase!

------
pka
Great! Now go for Haskell :)

