The Whiteboard Ritual

Every software engineer eventually faces the whiteboard interview. It's the standard gatekeeping ceremony of the industry, and reversing a linked list is one of its most common sacraments. But beneath the familiar ritual lies a deeper question: what are we actually testing for?

The conventional approach treats the interview as a performance. You're asked to write code on a board while an interviewer watches, and the entire exercise is staged around demonstrating that you can produce the expected answer under pressure. The unspoken rules are clear: use conventional syntax, name things descriptively, add docstrings, show your work.

An Alternative Approach

Consider a different path. When asked to produce a linked list, you might begin by establishing the foundation of your practice:

(defn cons [h t] #(if % h t))

The interviewer will likely object — this doesn't look like a list at all. But the response reveals a fundamental truth about representation:

user=> (def x (cons 1 (cons 2 nil)))
#'user/x
user=> (x true)
1
user=> ((x false) true)
2

What is x exactly? At the REPL, the answer is immediate:

user=> x
#object[user$cons$cell__4431 0x3b89cc1c "user$cons$cell__4431@3b89cc1c"]

In certain traditions, true names carry power. Assigning a letter of one's own identity to a language is to surrender a piece of oneself. This principle extends beyond naming conventions to the very structure of code.

Beyond the Conventional

When asked to retrieve an element, one might compose an expression of elegant recursion:

(defn nth [l n]
  (when l (if (= 0 n)
            (l true)
            (recur (l false) (dec n)))))

But the interviewer wants something more familiar. So you provide a conventional pretty printer:

(defn prn-list [l]
  (print "(")
  (loop [l l]
    (if (nil? l)
      (print ")\n")
      (do (print (l true))
          (when (l false)
            (print " "))
          (recur (l false))))))

Time pressure is a constant in this environment. Descriptive variables and documentation are luxuries you cannot afford — treat it as an exercise in extreme functional style:

user=> (prn-list (cons 1 (cons 2 (cons 3 nil))))
(1 2 3)

Once the interviewer sees something resembling standard practice, comfort returns. The question inevitably turns to reversal. In the classical approach, this is where iteration and careful pointer manipulation come into play. But there is a more compressed expression of the same concept:

(defn reverse [l]
  (loop [r nil, l l]
    (if l
      (recur (cons (l true) r) (l false))
      r)))

user=> (prn-list (reverse (cons 1 (cons 2 (cons 3 nil)))))
(3 2 1)

Reflections on the Process

The interview concludes politely, and the rejection follows soon after — typically framed as a cultural mismatch. But the exchange reveals something about our hiring practices: they privilege a narrow band of stylistic conformity over genuine technical depth. Different traditions of programming — each with rigorous foundations and internal logic — get filtered out because they don't match the expected pattern.

For those who don't fit the mold, the whiteboard ritual remains a gate that cannot be passed through honest expression, only navigated by mimicry.