I’ve been writing a lot of functional lisp lately for the first time and one thing that’s struck me is how easy it is to refactor. Because a form can always be reduced to its result, you can pluck them out, move them around, and evaluate them at any level of the tree. While this is true of functional programming in general the structure of lisp makes its super easy in a way it’s not in a Haskell or just functional JavaScript.
> struck me is how easy it is to refactor
Yes! After a few years of using Clojure for work; Fennel for configuring anything that requires Lua; Lisp-based editor, nbb and babashka for scripting — now I just can't deal with non-lispy languages without getting mentally and emotionally exhausted. It feels so taxing to have to deal with all the syntax elements, indentation, etc. So many times my thoughts got derailed due to a missing comma in some json or slightly misindented shit in yaml.
I just don't understand how I used to happily write programs before, and I did it for over a decade. Without ever being able to "transpose these two things around", "lift this structure and move it over here", "slurp this thing inside", "raise this expression", "wrap this piece into its own block", etc. And then the actual REPL — OMG, that's a song of its own accord.
Programmers with shallow understanding and lacking experience of Lisp (or straight bias against it) are missing out so much, it really is sad.
> Programmers with shallow understanding and lacking experience of Lisp (or straight bias against it) are missing out so much, it really is sad.
Most people I know of that tried Lisp and didn't like it did so by writing Lisp without structural editing, into a text file, starting a REPL, loading the entire file into the REPL and calling the main function from the REPL.
It's difficult to explain just how absurdly slow and cumbersome that is, as its the primary way developers work in other languages to the point that what you're saying sounds like hyperbole.
For those that haven't experienced that difference:
Structural editing when you have a homoiconic language that only has expressions is like combining expert level vim skills with vim macros and expert level IDE snippets/refactor shortcuts but with a fraction of the expertise as the tooling is simply less complicated.
REPL driven development is state retaining hot reload as a first class citizen, which makes regular compile cycles and the shenanigans you need to do to isolate your current code and make it run (eg. flags, rewriting main, writing tests) appear absurd in comparison.
By the time you add the features of Lisp systems on top (like condition restarts, runtime compilation, ASM inspection etc), most other languages feel like a big step back.
S-expressions really are the game changer. Especially in a functional lisp with immutable data structures. You can lift and shift forms around with reckless abandon and never cause a bug. You're not typing characters that eventually get parsed into a tree, you're building the tree! Programming in bespoke arrangements of ascii delimiters feels like regressing to punch cards.
> S-expressions really are the game changer.
I know, right? The hardest part is that no amount of explaining and convincing anyone who never tried truly grokking this aspect of the homoiconic nature of Lisps really moves the needle. It's like living in ancient Greece, trying to convince people that riding a bike is enormously fun. No matter how verbally you explain, no matter how many blueprints and drawings you produce — until you build one and teach someone to ride it, nothing would change — people will not believe you.
Same is true with Lisp; until you get to experience the structural editing and REPL-driven workflow yourself, you wouldn't even know what you're missing.
It is a bit more like that with React components, React tries to make JS be more like Lisp. Like the render functions are supposed to be stateless and so on...