Dan Midwood, a functional programmer working in Clojure and Scala, wrote an animated guide to structural editing of Lisp code with Emacs Paredit.
HN links the Paredit guide in discussions of tree editing; one commenter says it finally made Lisp and s-expressions click and led them to Clojure.
I can only speak from the perspective of using Clojure, I toyed around with Racket and have no experience with CL.
That said, I disagree with some of the points you make:
> availability of useful libraries
Clojure is embedded in both JS runtimes and the JVM. Both feature massive ecosystems.
In terms of getting things done:
Languages like Python, JS and so on are fantastic at plumbing. But when it comes to modelling data-structures, manipulation and algorithms then they are far less expressive and productive than Clojure from my experience.
I personally think the main issue really is the learning curve. There are quite a number of things that 'suck' about Clojure initially:
1. In a Lisp you are essentially manipulating an AST rather than writing statement-based text. Initially this is cumbersome and taxing both while reading and writing programs.
2. In a functional Lisp like Clojure (and other FP languages) there is a wide variety of commonly used functions which are used to manipulate and compose data-structures and other functions. Especially when reading code this can be daunting.
3. Setting up a environment correctly for REPL driven development as a beginner and tuning it as an intermediate user is quite an undertaking in comparison to many other languages.
4. Clojure specifically being a hosted language forces you to understand the hosted ecosystem as well plus the wiring between the host and Clojure.
The payoff for all those four points is worth it:
1.…
Being able to create code with code, allows you to do away with boilerplate code. E.g. if you got a lot of code with just minor differences, you can make those differences into parameters in a macro which makes each of these code chunks.
That can be utilized both at high level and low level. GOAL is a cool example: https://en.wikipedia.org/wiki/Game_Oriented_Assembly_Lisp. Basically you can express assembly code in LISP syntax and then you can create higher level constructs like if, while, for etc statements as macros composing these lower lever assembly instructions. Because data and code is the same in LISP that allowed Naughty Dog when they used GOAL on the Playstation 2, to swap chunks of code in and out of memory as needed easily to maintain larger levels than the competition. It is also something that allows you to change a running system. I believe there was a case of a malfunctioning satellite running LISP code, which was debugged and fixed while it was running. Shutting it down for fixing was not an option.
I would also add another benefit of only using parenthesis. It makes it really easy to make powerful tools for LISP. Have a look at s-expression based editing. Instead of working line by line, or word by word as we are used to with editors, these work with whole blocks of code at the time. Normal editor commands involve jumping word by word or line by line. with LISP editors you can view the code as a tree with keyboard commands for jumping between tree…
There are some built-in commands in Emacs for navigating, cutting and transposing s-exps, but what you want is probably a step further - a package like Paredit[0], that gives you much more sexp-specific actions, and automatically keeps parens balanced for you. See animated examples at [1] and a cheat sheet at [2].
There isn't, as far as I know, a default keybinding for what GP did - navigate up the SEXP, wrap in parens and place point before the inner SEXP. You can get very close to it with two steps: paredit-backward-up [C-M-u] and paredit-wrap-round [M-(], though it gets confused by the hanging quote a bit. To demonstrate on GP's example:
'(some data|)
'|(some data) ; after C-M-u
'(|(some data)) ; after M-(
So the quote is in a wrong place. You could probably whip a command doing OP's thing that calls paredit-backward-up and paredit-wrap-round, with a conditional that backs up a few chars if it detects a piece of syntactic sugar attached to the SEXP (quote, quasiquote, comma, reader macro invocation). Somebody has likely already done it, or maybe there is a less known Paredit command for that - I don't know. If anyone does, please chime in.
Myself, I mostly use wrapping, barfing and slurping.
--
[0] - Available in Emacs' package manager on MELPA, or here: https://github.com/emacsmirror/paredit.
[1] - http://danmidwood.com/content/2014/11/21/animated-paredit.html
[2] - https://github.com/joelittlejohn/paredit-cheatsheet
Unite, fireplace, rainbow parens, vim-sexp and vim-surround are all available in Emacs with its own and better implementation.
If you want Unite equivalent, check Helm which is created before Unite and is still actively maintained. See one of Helm package demo: http://tuhdo.github.io/helm-projectile.html. The same for rainbow-parentheses. Actually, Emacs got something better than rainbow-parentheses for visual aiding parentheses: https://github.com/syl20bnr/spacemacs/issues/1173
For proper sexp manipulation, check this guide with great animations: http://danmidwood.com/content/2014/11/21/animated-paredit.html
For Clojure, in Emacs you got a debugger than can step expression by expression: http://endlessparentheses.com/cider-debug-a-visual-interactive-debugger-for-clojure.html
If you want to know features for Clojure that already configured in Spacemacs, check its Clojure documentation: https://github.com/syl20bnr/spacemacs/tree/master/contrib/lang/clojure#features
You got all IDE features like refactoring and jump to symbols
More demos:
Here are some nice features that Emacs and its 3rd packages provide:
- Powerful automatic indentation with aggressive-indent: https://github.com/Malabarba/aggressive-indent-mode(scroll down for demos). It does not only indent the current line, but the whole semantic context around your cursor.
- Live grep:http://tuhdo.github.io/static/live_grep.gif
- C/C++ refactoring with built-in parser:…
This was the page that made me finally grasp why Lisp and s-expressions are relevant. After reading this about a year ago, I ended up picking up a Clojure book and now I'm enamored with s-expressions. I feel late to the party.
The last time I tried to learn Lisp (prior to reading this) was in like 2003/4 from some CLISP tutorial that scared me away from having nothing but math examples and zero explanation of the philosophy or design. It felt like an esoteric and purely academic language, and I brushed it off as not worth my time. (I was never really put off by the parens, and now I love them. Never understood that aspect of Lisp discourse. Once you learn ParEdit[1] you don't want to go back.)
Now I link this page whenever I want to explain to someone why there are "all these parens". It's dated, though, and associating s-expressions with JSON and JavaScript would probably be a more contemporary approach. Maybe I should rewrite this article for a modern developer audience.
[1]: http://danmidwood.com/content/2014/11/21/animated-paredit.html "GIFs of ParEdit in action"
An interesting idea that's definitely worth exploring.
However, I think the conflict between tree-based editing and normal editors is completely unnecessary. In fact, you can actually get basic tree-based editing today in Emacs!
The easiest language to support like this is Lisp because its syntax is about as close to pure tree as possible. And, indeed, Emacs has had structural editing for lisp for a while in the form of Paredit[1]. More recently, somebody extended this idea to Haskell[2] which is interesting because Haskell has one of the more complex, persnickety syntaxes around.
I'm not saying either of these are as good as dedicated editors—I'm not even convinced they could be as good—but they are low-cost ways to try these ideas out right now without abandoning general-purpose text editing or creating a brand new tool.
[1]: http://danmidwood.com/content/2014/11/21/animated-paredit.html
[2]: https://github.com/chrisdone/structured-haskell-mode