I Love Lisp

tacoda1 pts0 comments

Why I Love Lisp. I learned to read math notation before… | by Ian Johnson | Jun, 2026 | MediumSitemapOpen in appSign up<br>Sign in

Medium Logo

Get app<br>Write

Search

Sign up<br>Sign in

Why I Love Lisp

Ian Johnson

6 min read·<br>Just now

Listen

Share

I learned to read math notation before I learned to read code. By the time I sat down with a programming book in college, I had spent years writing function compositions, defining sets by predicates, and turning one expression into another by substitution. The shape of math was already in my head.<br>The first language I tried to learn was Java. The mismatch was immediate. The math I knew did not have classes; it did not have getters and setters; it did not have a main method with a String[] args parameter. The math I knew had functions, and the functions composed.<br>A few years later I discovered Scheme. I had the opposite reaction. This was not a programming language pretending to be math. This was math that happened to run.<br>Functions all the way down<br>Lisp’s primary abstraction is the function. Not the object, not the class, not the module: the function. Everything else is built on top.<br>The intellectual root is the lambda calculus, which is older than computers themselves: a formal system with one operation (function application) and one rule (substitution). McCarthy took the lambda calculus and gave it a syntax you could type. The language fell out almost immediately.<br>A data structure is a function in disguise; a list is a constructor and two accessors. An object, when you need one, is a closure over some state. A control structure is a procedure that takes other procedures as arguments. The vocabulary is small and the recursion is total.<br>For someone with a math background, this is the language sitting where you expect it to sit. In math, a function is the unit of thought. You name it, you compose it, you reason about it. You do not wrap it in a class to give it a home. Lisp agrees.<br>The syntax is the abstract syntax tree<br>Most languages have a syntax that the compiler parses into a tree. Lisp skips the parse. The syntax is the tree. Parentheses are not punctuation; they are the structure.<br>(+ 1 (* 2 3))This is a tree with + at the root and two children: the leaf 1 and a subtree rooted at *. Prefix notation, the way a mathematician writes an abstract expression. There is nothing to parse around.<br>The shape also reads close to natural speech. (add 1 2) is verb-then-objects, the way you would say it: “add 1 and 2.” Java’s Integer.sum(1, 2) is a noun, a dot, and a verb that takes arguments, which is no English clause I recognize. The prefix order matches how a person describes an action.<br>The deeper payoff is that code is data. The expression above is also a list of three elements. A program can read it, transform it, and evaluate the result. The boundary between “the program” and “the program’s input” disappears.<br>Macros and the death of patterns<br>The first time I wrote a macro, I understood what people meant by patterns are where you run out of language .<br>A design pattern is a workaround for something the language cannot say directly. Visitor is a workaround for the absence of multimethods. Strategy is a workaround for the absence of first-class functions. The Gang of Four book is, read uncharitably, a list of features Java did not have in 1994.<br>In Lisp, when you find yourself writing the same shape of code twice, you write a macro. The macro does not look like a workaround; it looks like new syntax. The third time you need the pattern, you use the syntax. The pattern is not a pattern anymore; it is a word in the language.<br>This is the deepest version of the DSL idea, and Lisp is where the DSL idea was born. You do not write a program in the language. You write a language for the problem, then you write the program in that. The line between “library” and “language extension” stops being load-bearing.<br>Concepts you stop needing<br>Working in Lisp deletes concepts I had thought were fundamental.<br>I do not need a for loop; I have map, filter, and reduce. I do not need a class hierarchy; I have closures. I do not need a builder pattern; I have functions that return functions. I do not need a null check at every callsite; I have option types and pattern matching.<br>The list is not “Lisp has cleverer ways to do these things.” The list is “Lisp does not have these things, and the absence is not a hole.” The concept stopped being necessary when the abstraction underneath it got simpler.<br>This is the part of the language I find most clarifying. Subtraction as design.<br>Pure functions and honest side effects<br>A Lisp program tends to separate the part that computes from the part that touches the world. Pure functions in the middle; effects at the edges. The middle is easy to test, because a pure function is its inputs and its output and nothing else. The edges are explicit, because the language gives you nowhere to hide them.<br>Clojure makes the discipline more obvious than Scheme does: immutable...

lisp language math functions function syntax

Related Articles