LISP

1958年に生まれた、現存する最古の高級言語の一つ。「コードとデータが同じ構造」という設計思想を持つ。

プログラマ向けの一言

すべてがリスト。関数呼び出しも (関数名 引数1 引数2) というリスト。 コード自体がデータ構造なので、プログラムがプログラムを生成・変換することが自然にできる。

コードで理解する

// LISP の S式を TS で表現すると、すべてが配列になる
type SExpr = number | string | SExpr[];

// LISP:  (+ 1 2)
// TS:    ["+", 1, 2]

// LISP:  (define (square x) (* x x))
// TS:    ["define", ["square", "x"], ["*", "x", "x"]]

// 超簡易 LISP 評価器
function evaluate(expr: SExpr, env: Map<string, any> = new Map()): any {
  if (typeof expr === "number") return expr;
  if (typeof expr === "string") return env.get(expr);
  if (!Array.isArray(expr)) return expr;

  const [op, ...args] = expr;
  switch (op) {
    case "+": return evaluate(args[0], env) + evaluate(args[1], env);
    case "*": return evaluate(args[0], env) * evaluate(args[1], env);
    case "if":
      return evaluate(args[0], env)
        ? evaluate(args[1], env)
        : evaluate(args[2], env);
    default:
      const fn = env.get(op as string);
      return fn(...args.map(a => evaluate(a, env)));
  }
}

evaluate(["+", 1, ["*", 2, 3]]); // 7

ホモイコニシティ(同図像性)

// LISP の最大の特徴: コード = データ
// コードがリストなので、プログラムでコードを操作できる

// マクロの概念: コードを受け取ってコードを返す関数
// LISP の unless マクロ(if の逆)
// (unless condition body) → (if (not condition) body)
function macroUnless(expr: SExpr[]): SExpr[] {
  const [_, condition, body] = expr;
  return ["if", ["not", condition], body]; // コードを組み替えて返す
}

// これが TS/JS にはできない(AST を直接操作する手段がない)
// LISP ではこれが言語の標準機能

マクロの落とし穴は変数捕捉(マクロが展開先の変数を意図せず巻き込む)。Common Lisp は gensym で一意なシンボルを作って手で避け、Scheme の syntax-rules は衛生的マクロ (hygienic macro) が自動で防ぐ。コード=データゆえ構文そのものを作れる = DSL を言語内で構築できるのが Lisp 最大の実用的帰結。

Lisp が先取りした概念

現代言語が「新機能」として取り込んだものの多くは Lisp 由来。Lisp は 1958 年時点で先回りしていた。

概念Lisp での起源後発への波及
ガベージコレクションMcCarthy (1959)Java/Go/JS… ほぼ全マネージド言語
第一級・高階関数関数 = 値JS/Python/Rust のクロージャ
条件式 cond / 再帰中心Lispほぼ全言語
動的型付けLispPython/Ruby/JS
REPL(対話的評価)Lisp各言語の対話環境
マクロ / 同図像性S 式 = コードRust の macro、Elixir、テンプレート系
condition system(再開可能例外)Common Lisp多くの言語が未追随

Greenspun の第10法則: 「十分に複雑な C / Fortran プログラムは、Common Lisp の半分をその場しのぎでバグだらけに再実装したものを含む」— 言語が結局 Lisp の機能を再発明する、という皮肉。

方言

方言性格マクロ特徴
Common Lisp実用・大規模非衛生 defmacroCLOS(多重ディスパッチ)、condition system、巨大標準
Schemeミニマル・教育(SICP)衛生的 syntax-rules継続 [[continuation|call/cc]] が一級。仕様が小さい
ClojureJVM 上のモダン Lispdefmacro + syntax-quoteイミュータブル永続データ構造・STM
Emacs LispEmacs の拡張言語defmacroエディタ全体の実装言語。動的束縛の歴史
Racket言語を作る言語強力なマクロ系#lang で DSL / 新言語を量産

押さえどころ(カード化候補)

関連

Graph