Pinky beige thumbnail with

All Lisp Indentation Schemes Are Ugly | line4k – The Ultimate IPTV Experience – Watch Anytime, Anywhere

Streaming Service Promotion

Ready for uninterrupted streaming? Visit us for exclusive deals!
netflix youtubetv starzplay skysport showtime primevideo appletv amc beinsport disney discovery hbo global fubotv
netflix youtubetv starzplay skysport showtime primevideo appletv amc beinsport disney discovery hbo global fubotv

By Artyom Bologov

Once you get used to Lisp, you stop noticing the parentheses and rely on indentation instead.
That’s partially why there are several alternative syntaxes based solely on indentation.
Like Wisp,
or sweet expressions.
But then, the question stands: how to indent the code, actually?
Especially so—in Lispy syntax.

A solution that will likely satisfy a proponent of any indentation style:
“Just put it all on one line lol.”
Of course, lines are not infinitely readable and there’s a column cap,
(whether natural or enforced.)
So this line (adapted from
cl-blc,)
while devoid of indentation problems, is unreadable:

(list (tree-transform-if predicate transformer (first tree) depth) (tree-transform-if predicate transformer (second tree) depth))
Absurdly long line of a Lisp code

That’s the problem statement: some forms need multiple lines and indentation.
But what kind of indentation?

There’s an established style of indentation: align the function arguments on the same column:

(list (tree-transform-if predicate transformer (first tree) depth)
      (tree-transform-if predicate transformer (second tree) depth))
(inc! d (/ (* (mtx:get x i k)
              (mtx:get x j k))
           (1+ (* (vec:get dl l)
                  (vec:get eval k)))))
(let ((s (if (< j i) j i))
      (l (if (< j i) i j)))
  (+ (* s 1/2 (- (* 2 d-size) (1+ s)))
     l
     (- s)))
Examples of function-like indentation

This style if useful in reflecting the code structure: just look at what’s indented and what’s outdented.
It works especially well for short function/macro/form names, like + or vec:get.
Not so well for long ones:

(tree-transform-if predicate
                   transformer
                   (second tree)
                   depth)
A problematic function indentation

Nineteen!
Nineteen spaces of indentation!
It’s getting unruly.
Such an indent, when used in deeply nested code, makes it too wide and unreadable.
If you add the strict one-per-line alignment of arguments, it’s also painfully long line-wise.
Let’s handle the verticality first:

No sane Lisper would write a loop with every keyword on its own line:

(loop for
      i
      below
      10
      collect
      i)
Ugly loop

(Some pretty-printers do that too (I’m looking at you, ECL!), but that’s a topic for another day.)

We don’t have to put every argument on its own line.
That’s the intuition behind the space-filling indent:

(loop for i below 10
      collect i)
Less ugly loop

One can go as far as splitting the argument list in arbitrary places.
Regardless of semantics.
(Looking at you, SBCL!)
Putting some keyword arguments on the first line, and then some on the second/third/etc.
This utilizes the space efficiently enough to be used.
But what if one’s stuck really deep in nesting levels?

Now what I’m about to suggest is likely not to your taste:

(tree-transform-if
 predicate transformer (second tree) depth)
My indentation style suited for deeply nested code

This style of indentation
(putting function name on one line, and arguments on the other)
was frowned upon more than once in my practice:

  • It messes up with nesting identification: one space is not enough.
  • It makes the code too vertical.
  • And it certainly isn’t idiomatic.

But what this style achieves is perfect indentation control.
You only get one space of indentation per form.
Complex algorithms are easier to read when written in this style.

And!
This style also plays well with most indentation tools, even the simplest ones.
I had this situation more than once:

  • Writing a with-* macro in Scheme;
  • Using it;
  • And realizing that Emacs/Geiser indentation functions think that this macro is a procedure.

Indenting all the arguments of the progn/begin-like macro in this sick style helps:

;; From
(mtx:with-column (uab-col uab index-ab)
                 (mtx:set!
                  ppab 0 index-ab
                  (blas:dot hi-hi-eval uab-col)))
;; To
(mtx:with-column
 (uab-col uab index-ab)
 (mtx:set!
  ppab 0 index-ab
  (blas:dot hi-hi-eval uab-col)))
Sick indent helps you to manage macros

I worked on a deeply nested corporate codebase functions.
In Clojure.
And I realized why threading macros exist.
To make the logic more sequential and readable, true.
But also to tame excessive nesting!

Unfortunately, threading/arrow macros don’t always work.
Common Lisp in particular is extremely unfriendly to threading macros.
Arrows imply a consistent thread-first or thread-last functions.
But CL’s standard lib is too inconsistent for that to work.
So we’re left with picking an indentation style we don’t necessarily like.

I often prefer the macro-like indentation, because I sometimes write deeply nested code.
But I see the value in all the other indentation schemes!

This website is
Designed to Last
and generated on
Sun Jan 19 16:53:39 +04 2025
with the help of
ed(1).
You can view page sources by appending .htm to the page URL.
You can also view alternative .txt, .gmi, .7 (man), and .tex versions this way.

Copyright 2022-2024 Artyom Bologov (aartaka).
Any and all opinions listed here are my own and not representative of my employers; future, past and present.

Premium IPTV Experience with line4k

Experience the ultimate entertainment with our premium IPTV service. Watch your favorite channels, movies, and sports events in stunning 4K quality. Enjoy seamless streaming with zero buffering and access to over 10,000+ channels worldwide.

Live Sports & Events in 4K Quality
24/7 Customer Support
Multi-device Compatibility
Start Streaming Now
Sports Channels


line4k

Premium IPTV Experience • 28,000+ Channels • 4K Quality


28,000+

Live Channels


140,000+

Movies & Shows


99.9%

Uptime

Start Streaming Today

Experience premium entertainment with our special trial offer


Get Started Now

Scroll to Top