-
Notifications
You must be signed in to change notification settings - Fork 20
Clojure
tldr; LISP on JVM
Clojure is a dynamic, general-purpose programming language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a compiled language, yet remains completely dynamic – every feature supported by Clojure is supported at runtime. Clojure provides easy access to the Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection.
Community Docs: Much better than the official, has examples.
Reference: Useful, advanced documentation written by core contributors.
API Docs: Just the exported navigable API docs.
Don't use Ant, Gradle or Maven. Use Leiningen.
There is a Clojure plugin for IntelliJ IDEA, which will give you the best experience if you like IDEs, and don't want to use Emacs. Proprietary, free for non-commercial use, acquire a license from their site: https://cursive-ide.com/
An absolute must have. Auto-balances parentheses on insertion and does other nice stuff making editing LISP fun.
Search for Structural editing in Settings to enable it. I use the ParEdit style. Works with IdeaVim, but you'll need to remap some stuff.
Move Down/Up => exchange form under caret with next/previous form
Slurp Left/Right => extend surrounding parentheses to include next form to the left/right
Barf Left/Right => shrink surrounding parentheses to exclude leftmost/rightmost form
Raise => replace surrounding parentheses with form under caret
Kill Sexp => delete form under caret
Kill => delete everything to the right of caret until closing brace
Split => split surrounding parentheses into two at caret
Join => join preceding parentheses with parentheses under cursor
tldr; Using Cursive's Reformat code action will give you a pretty good formatting. Use your brain to learn the style.
LISP code is indented differently than C-like languages. Clear your mind, don't try to apply rules learned there.
Opening brace should be on the same line as the first form in it. Closing brace should be on the same line as the last form in it.
✅ DO
((((good)
(good)
(good))))
❌ DON'T
(
(
(
(bad))))
((((bad)
)
)
)
You may move the second or later forms onto a new line. The indent depends on the opening parenthesis' position. Add 2 spaces to that if you move the second form, make it line up with the second if that remains on the first line:
✅ DO
(this (is (a
(good (way) ; second is on new line so I added 2 spaces
(hur-) ; second is on the first line, third lined up
(ray)))))
❌ DON'T
(this (is (a
(bad
(way)
(may)
(day)))))
You are encouraged to use multiple ;
s to signify how mature that comment is. Of course the most
important stuff should be in docstrings. For less important or sound stuff:
-
;;
when a comment is near doc level. Documentation for single functions that extends beyond the doc string (e.g. an explanation of the algorithm within the function) -
;
In-line comments possibly on a single line, and possibly tailing a line of code
Use the REPL. Super fast, and you get immediate feedback.
You should create a REPL for your project then Run REPL for MyProject. You'll have a lot of convenience actions. My favourites are:
- Send form under caret to REPL
- Send top form to REPL
- Load file in REPL
- Run tests in namespace in REPL
- Run test under caret in REPL
- Re-run last test action in REPL
Note: when you send a form to the REPL, its namespace is retained. If that namespace isn't loaded yet in the REPL, you won't have anything it require
s, not even clojure.core
(most likely it uses in-ns
) resulting in strange errors such as that defn
is unbound and such. So either send the whole file first, so you get the namespace declaration, or you have an option in Settings to set the form's namespace to the current namespace in the REPL when it is sent.
Clojure is a dynamic language. Use the Eastwood lint tool to prevent some common errors and unidiomatic code.