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:
Because -> is not a typical functional idiom, it's a macro specific to Clojure, and anything you can do with -> you can also do in the standard functional way, and beginners are better served by understanding the way a lisp works rather than only get taught syntactic sugars. Keep in mind that -> as a macro does not evaluate its arguments the way a function does, which complicates the understanding for a beginner tremendously, since Clojure is actually an eagerly-evaluated language.
Ha, yeah, I get where you're coming from. And I toyed with putting a threading macro example inline, and in the end put a footnote in instead.
My reasoning was that basically, regardless of the threading macros, you are going to have to learn to read/write s-expressions as-is for a couple of reasons:
1. The threading macros won't be the best way forward in all cases.
2. You're going to need to read other people's code, which wasn't using the macros.
Overall, I was trying to make the point that it is a real hurdle (at least that's how it felt for me), but worth getting over. As a week or so later, you can read s-expressions with relative ease. That it's worth making the effort, because they are pretty awesome. Maybe I just didn't communicate that very well.
Good point. My code is littered with threading macros all over the place, and it can really reduce ))))))))))) to ). But I wouldn't have been able to use it effectively if I didn't know how s-expressions work.
This is subjective and dependent on the background. I, as a beginner, found the original expression easier to understand, whereas, the "->" macro rewrite seems puzzling. Specially (map #(+ % 2)) looks as if the values are summed and then % 2 is applies to it.
As a Clojure/Lisp beginner, I can't say I agree. I don't know any language that works like your example, except maybe shell script with its pipes. Without variables, that expression just seems too "magical". Nested function calls, on the other hand, are common everywhere.
While they might make the flow clearer, I don't think the swiss arrows fix what I perceive as more confusing for a newcomer.
The problem is that -<> looks like a regular function call, but does things that a function call can't do. In a language without macros, which are most of the mainstream ones, <> would have to be a language feature, and then it's not clear why you'd need to use -<> to 'activate' it.
Now, I've read enough about Lisp and AST and such to understand what a macro is, but the concept doesn't map easily to mainstream languages.
...that's how chaining method calls end up working in most OO languages (take the Scala example in OP's article). And also in Javascript (I can't remember if there is something like `range` in js right now...):
[1,2,3,4,5,6,7,8,9,10]
.map(function (x) { return x + 2 })
.reduce(function (a, b) { return a + b })
so the "." in OOP ends up working like "->" or "->>". Heck, you can make the dot in OOP code behave like anything, even like monadic bind (`>>=` or `do` notation in Haskell), if you do OOP-style-monads in JS: https://www.youtube.com/watch?v=b0EF0VTs9Dc
(off-topic: this is also my main problem with OOP... the "." can actually end up meaning anything practically, as program logic is concerned, it's like some kind of "infinite operator overloading" :) )
But (conceptually) the "." in most OO languages is something that is part of the object it's being applied to, while the -> is something external that one applies to the subsequent expressions. At least, this is what I perceive by looking at the code, and in my opinion, the two concepts don't map intuitively.
Why other Lisp tutorials don't teach -> is, firstly, that other Lisp's don't have that, except as some add-on library feature. Secondly, it's a syntactic sugar that has quite a bit going on under the hood: implicit parameters, a lambda function being expressed as #(+ % 2) with this % thingy, and return values of forms being passed as arguments to other forms that are not syntactically enclosed. You have to understand that (range 10) is just called normally, but then its return value becomes an extra invisible argument to the (map ...) form.
Newcomers should learn the underlying ordinary evaluation first.
Totally agree with your point, but just a quick note: using the thread-first -> macro won't work in this case, instead you'd use the thread-last macro ->>. Also Clojure doesn't have a sum function, so you'd actually use (reduce +).
only in this case, it should be ->>, because -> inserts argument into first position, but you need it in the last... And you can omit parentheses around functions without additional arguments (sum in this case)
EDIT: as observed by others, `->` should actually be `->>`, sorry for the typo, but unfortunately I can't edit the original comment anymore. Also forgot there's no "sum" already defined in Clojure, so replace that with `(reduce +)`
This is almost close to showing a code snippet like this to someone trying to learn Haskell:
(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...)...really, people, stop scaring learners away!