Two Philosophies from a Common Ancestor
Both languages descend from McCarthy's original LISP, but Scheme, designed by Guy Steele and Gerald Sussman in 1975, pursued minimalism — a small, orthogonal core language defined precisely enough to fit in the R7RS standard's roughly 90 pages — while Common Lisp, standardized in 1994 as ANSI X3.226, deliberately unified and grew the feature sets of several earlier dialects (MacLisp, InterLisp, Zetalisp) into a single, large, industrial-strength standard exceeding 1000 pages. This isn't an accident of history so much as a design stance: Scheme asks 'what is the smallest set of primitives from which everything else can be built,' while Common Lisp asks 'what does a professional programmer need available without having to build it themselves.'
Cricket analogy: Scheme is like a backyard cricket rule set stripped to just bat, ball, and stumps, letting kids derive their own rules for boundaries and overs, while Common Lisp is like the full ICC playing conditions manual specifying DRS, powerplays, and over-rate penalties in exhaustive detail.
One Namespace vs Two: Lisp-1 vs Lisp-2
The most consequential technical difference is that Scheme is a Lisp-1: functions and variables share a single namespace, so ((lambda (f) (f 5)) (lambda (x) (* x x))) works with f used directly as a function because there's no ambiguity to resolve. Common Lisp is a Lisp-2: functions and variables live in separate namespaces, so calling a function requires funcall or apply when the function is stored in a variable — (funcall f 5) — while (f 5) would instead look up f in the function namespace directly. This split lets Common Lisp use the same symbol as both a variable name and a function name without collision (like list, the function, vs a variable named list), but it means passing functions around requires more ceremony than in Scheme.
Cricket analogy: Scheme's single namespace is like a stadium where the same gate number always means the same thing whether you're a spectator or a player, while Common Lisp is like a stadium with separate spectator-gate and player-gate numbering systems that happen to reuse the same digits for different purposes.
Tail Calls, CLOS, and the Standard Library
R7RS Scheme mandates proper tail-call optimization: any call in tail position must not grow the stack, which makes iteration-via-recursion a reliable, idiomatic pattern in Scheme in a way it is not guaranteed to be in Common Lisp, where tail-call optimization is implementation-dependent (SBCL does it under most optimization settings, but the standard doesn't require it, so loop or do is the portable choice for iteration). Conversely, Common Lisp ships CLOS, a comprehensive object system with multiple dispatch and multiple inheritance built into the standard, plus a large standard library (format, loop, extensive sequence functions), whereas Scheme's standard is deliberately silent on an object system and leaves most of a 'batteries included' library to SRFIs or implementation-specific extensions like Racket's.
Cricket analogy: Guaranteed tail calls are like a bowler's action being certified legal by every umpire in every match without exception, while Common Lisp's optional TCO is like an action that passes scrutiny under some umpires' interpretations but isn't guaranteed everywhere, so bowlers use a safer, more conventional action to be sure.
;; Scheme (R7RS): guaranteed tail-call optimization, single namespace
(define (count-down n)
(if (= n 0)
'done
(count-down (- n 1)))) ; guaranteed constant stack space
;; Common Lisp: portable iteration uses loop/do, not recursion,
;; because TCO is implementation-dependent
(defun count-down (n)
(loop for i from n downto 0
finally (return 'done)))
;; Lisp-2 in action: 'list' as both a function and a variable name
(defun show-both (list)
(funcall #'list list 'extra)) ; #'list refers to the function
(show-both '(1 2 3)) ; => ((1 2 3) EXTRA)Racket, one of the most widely used Scheme descendants, deliberately diverges from minimalist R7RS Scheme by shipping a huge batteries-included standard library and its own object system, showing that 'Scheme' in practice spans everything from strict minimalism to a fully industrial platform.
Code that relies on deep self-recursion for iteration is safe and idiomatic in standard-conformant Scheme but can silently blow the stack in Common Lisp on an implementation or optimization setting that doesn't perform tail-call elimination — always prefer loop, do, or an explicit iteration construct for portable Common Lisp code.
- Scheme (R7RS) pursues a small, minimalist standard; Common Lisp (ANSI X3.226) is a large, industrial standard unifying earlier dialects.
- Scheme is a Lisp-1 with one namespace for functions and variables; Common Lisp is a Lisp-2 with separate namespaces.
- Calling a function stored in a variable requires funcall or apply in Common Lisp, but is direct in Scheme.
- R7RS Scheme mandates proper tail-call optimization; Common Lisp's TCO is implementation-dependent, not guaranteed by the standard.
- Common Lisp ships CLOS, a full multiple-dispatch object system, built into the standard.
- Scheme's standard is silent on an object system, leaving it to implementations or SRFIs.
- Racket shows that real-world Scheme implementations can diverge far from R7RS minimalism toward a large standard library.
Practice what you learned
1. What is the core distinction between a Lisp-1 and a Lisp-2?
2. Why does Common Lisp require funcall to call a function stored in a variable, while Scheme does not?
3. Which statement about tail-call optimization (TCO) is correct?
4. What object system does the Common Lisp standard include that the Scheme standard does not?
5. Approximately how do the R7RS Scheme and ANSI Common Lisp standards compare in size and design philosophy?
Was this page helpful?
You May Also Like
LISP for AI and Symbolic Computing
Why LISP became the historical language of AI research, and how homoiconicity, symbolic data, and macros support symbolic reasoning, search, and rule-based systems.
Error Handling and Conditions
How Common Lisp's condition system goes beyond try/catch, letting programs signal, inspect, and interactively recover from errors using restarts.
Quicklisp and Package Management
How Quicklisp and ASDF work together to define, load, and distribute Common Lisp systems and their dependencies.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics