
2026/08/22 23:08
Racket の親しみやすい入門ガイド
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
1958 年に MIT で起源をたどり、現在も使用されている高水準言語の中で 2 番目に古い Lisp は、廃棄物回収、一等関数、REPL、ホモアイコニシティといった革命的な概念の先駆者として知られています。その固有のホモアイコニシティ—that is, code をそれを操作するデータ構造として表現できる能力—is 強力なマクロを用いて他のプログラムを書くプログラムを構築することを可能にします。かつては専用ハードウェアにおける人工知能研究の中心だった Lisp は、「AI 冬」と呼ばれる資金減少を経てから、主要企業による採用もあり驚くべき復興を遂げています。現在では、Google(フライト検索エンジンで Common Lisp/SBCL を使用)や Nubank(Clojure で銀行プラットフォームを実行)といった大手企業がこれらの方言を重要な生産システムに利用しています。生態系は Emacs Lisp(開発環境用)、Guile/Guix(Scheme で構成された Linux ディストリビューション)、言語志向プログラミングと教育に焦点を当てた Racket を含む多様な専門的なディストリビューションを支援しています。数十年の遺産を活用して現代のデータ密集型の課題を解決することにより、1950 年代に設計された言語が依然として重要な資産であることを Lisp は証明し続けています。この言語の基礎となる構文は括弧(
(operator argument...))に依存しており、すべてが表現であり、ユーザーは lambda を用いて値や名前無関数を定義し、cons および map などのツールを使用して基本的なリスト構造を操作できます。本文
リズプ(Racket)入門:コードはデータであり、構造は丸括弧
「リズプを学ぶ価値は、あなたがようやくその本質を理解した時に迎える、深い啓示体験にあります。」 —— エリック・S・レイモンド
プログラミングの最も古くとも特徴的な系譜の一つ。ここではコードがデータであり、丸括弧が純粋な構造を意味し、プログラム自体が他のプログラムを書くことができる世界にようこそ。このチュートリアルを終える頃には、あなた自身が独自の構文を作成する能力を手に入れることになります。
歴史のほんの一部
リズプは 1958 年 に MIT でジョン・マカルティによって誕生しました。現在の高級言語の中で二位に位置します(一年早く登場したフォートランだけがそれを上回っています)。Python(1991 年)や JavaScript(1995 年)などから30 年以上も先行しており、現在「現代的」と考えられているいくつかのアイデアはここで生まれました。
- ガベージコレクション —— リズプのために考案されました。
- 一等関数 —— 関数を引数として渡す仕組みで、現在は標準になっています。
- REPL —— Python や Node.js のようなインタラクティブな「読み・評価・出力のループ」はリズプから始まりました。
- 式としての条件文 —— 値を返す
表現です。if - ホモアイコニシティ(同構性) —— コードが言語自体のデータ構造として記述される特性です。これが最も重要な点です。
長年にわたりリズプは人工知能の主要な言語でした。1970〜80 年代には専用コンピュータ「リズプマシン」が開発されましたが、AI の冬の訪れにより主流から外れ、一部の愛好者だけが使用する宗教的な言語へと姿を変えました。しかし、思想や概念が消えることはありません。それらが変容し続けるのです——それがリズプ系の美しさでもあります。
リズプからスキームへ、そしてラケットへ
1975 年、ジェラルド・サスマンとガイ・スティーラーは、極小でエレガントな「スキーム」というリズプの派生言語を作成しました。
- 学界のおavorite 言語となり、伝説的な書籍『コンピュータプログラムの構造と解釈(SICP)』もスキームで書かれています。
1995 年、マティアス・フェルライセンの研究チームは「PLT スキーム」を開発しました。
- 2010 年 に名前を**「ラケット(Racket)」**に変更されました。
- 現在は単なる派生版を超えた存在へ成長し、「言語のための言語」と呼ばれます。
- 非公式なスローガン:「言語志向プログラミング(Language-Oriented Programming)」。問題に合わせて独自の言語をその日に一つ作れます。
歴史タイムライン
- 1958 年 —— マカルティが MIT でリズプを発明
- 1975 年 —— サスマンとスティーラーがスキームを創出
- 1984 年 —— Common Lisp が標準化される
- 1995 年 —— PLT スキーム(現在のラケット)が誕生
- 2007 年 —— クロージャ(JVM 上で動作するリズプ)が誕生
- 2010 年 —— PLT スキームが「ラケット」として改名
- 今 —— あなたがこの文章を読み、次の瞬間に丸括弧を書く準備をしているところ
今日リズプを使っているのは誰?
思いのほか多くの人が利用しています:
- Clojure —— 銀行(例:Nubank)、航空会社、スタートアップの本番環境で稼働。
- Common Lisp —— エキスパートシステム、フライトプランニング(Google Flights のバックエンド)、科学計算などで活躍。
- Emacs Lisp —— 何百万人もの人が気づかないうちに毎日実行しており、エディタ自体がリズプインタプリターだからです。
- Guile / Guix —— スキームで 100%構成された Linux 分布システム全体。
- ラケット —— RacketCon を開催し、学術的・芸術的なコミュニティを持っており、プログラミング言語の研究、形式検証(Rosette)、タイポグラフィと出版(Pollen)などで活用されています。
さらに新たなリズプ系言語も続々と登場:
- Fennel —— Lua にコンパイルするゲーム向け言語。
- Janet
- Hy —— Python を基盤にした言語。
TADC ファンのためのイースターエッグ:
『Amazing Digital Circus』第 8 話において、クリエイティブ AI「ケイン」の実装言語はリズプであることが確認できます。ファイル名は literal にとあります。Caine-core.lisp
インストール(5 分間)
- https://racket-lang.org にアクセスします。
- 自身の OS(Linux、macOS、Windows)に適したインストーラーをダウンロードします。
- 同梱された開発環境である DrRacket を起動します。
DrRacket の構造
- 上部: 定義エリア(プログラム本体)
- 下部: REPL(読み・評価・出力のループ)
定義エリアの第一行には必ず次のように記述します:
#lang racket
この行は、Racket においてどの言語バージョンを使用するかを指定する役割を果たします。ラケットは「言語工場」であり、特定の言語を選択する必要があります。
ターミナルでの利用
コマンドで REPL を起動します。racket
はパッケージ管理やツール系コマンドとして機能します。raco
REPL での初体験
> (+ 1 2) 3 > (* 3 (+ 2 2)) 12 > (string-append "hello " "world") "hello world"
リズプのルールは一言で表せます:
すべては
の形式です。常に。例外はありません。(演算子 引数 1 引数 2 ...)
- 演算子の優先順位を暗記する必要がありません。
- 特別な構文も一切ありません。
は足し算、(+ 1 2)
は条件判断、(if ...)
は名前の付与を行います。(define ...)
一見恐ろしく見える丸括弧は、任意の規則がまったくないことを示しています。一週間も経つと、すっかり気にならなくなります。
定義と関数
#lang racket (define pi-approx 3.14159) (define (circle-area r) (* pi-approx r r)) (circle-area 2) ; => 12.56636
で名前だけ指定すると定数が作成されます。define
にdefine
の形式を付けている場合は関数が作成されます。(名前 引数...)- コメントは分点番号の
で始まります。;
アノニマス関数(匿名関数)
名前のない関数には
lambda を使用します:
(lambda (x) (* x x)) ; 名前がない関数 ((lambda (x) (* x x)) 5) ; => 25、直接適用した場合
リスト:リズプの心臓部
「LISt Processing」がリズプの名前の由来です。リストは基本的なデータ構造となります:
(list 1 2 3) ; => '(1 2 3) '(1 2 3) ; 同じもの、ただし「引用済み」という意味 (first '(1 2 3)) ; => 1 (rest '(1 2 3)) ; => '(2 3) (cons 0 '(1 2 3)) ; => '(0 1 2 3) (length '(a b c)) ; => 3
重要:
という引用記号は、Racket に**「これを評価しないでください。これはデータです」**と指示しています。この細部を記憶しておいてください——最終的なトリックへの扉になります。'
高次関数
ラケットの真価が発揮される場所です。関数を他の関数の引数として渡すことは、最も自然な操作の一つです:
(map (lambda (x) (* x x)) '(1 2 3 4 5)) ; => '(1 4 9 16 25) (filter even? '(1 2 3 4 5 6)) ; => '(2 4 6) (foldl + 0 '(1 2 3 4 5)) ; => 15
が変換し、map
が選択し、filter
が累積します。foldl- これら三つの関数だけでリスト処理の問題の大部分を解決でき、for ループを書く必要もありません。
再帰:スパイラル的思考
リズプでは「N 回繰り返す」という発想ではなく、**「基本ケースは何か、それに向かってどう近づくか」**という視点を持ちます:
(define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1))))) (factorial 5) ; => 120
視覚的に理解できるよう、何かを描画してみましょう。ラケットにはグラフィックスライブラリが標準で含まれています:
#lang racket (require 2htdp/image) (define (sierpinski level) (if (= level 0) (triangle 8 "solid" "purple") (let ([t (sierpinski (- level 1))]) (above t (beside t t))))) (sierpinski 6)
DrRacket に貼り付け、実行ボタンを押すと、スクリーン上にシエプンスキ三角形的な図形が現れます。
ゴールドスタンダード:コードがコードを書く
再び引用記号
' を思い出してください——それはコードをデータに変換します:
'(+ 1 2) ; => リスト (+ 1 2)、数値 3 はでない (first '(+ 1 2)) ; => シンボル + (eval '(+ 1 2)) ; => 3、まさにデータをコードとして評価したことになります
- あなたのプログラムはリストそのものです。
- リストを構築できます。つまり、プログラムを使って他のプログラムも構築できるのです。
- これがホモアイコニシティであり、リズプが真のマクロを持つ理由です(C 言語のようなテキストベースのマクロではなく、実行前にコードを受け取りコードを返す関数としてのマクロです)。
ラケットに while ループがない?自分で一つ作りましょう
(define-syntax-rule (while condition body ...) (let loop () (when condition body ... (loop)))) (define counter 0) (while (< counter 5) (displayln counter) (set! counter (+ counter 1)))
これで言語自体を拡張しました。リズプの世界では、構文もあなたのものであり得ます。
アラン・ケイはリズプを「ソフトウェアのマクスウェルの方程式」と称し、「そこからすべての他の概念が導き出せる微小な核」であると表現しました。
次のステップ
- How to Design Programs —— ラケットの設計思想に基づいた教科書で、無料でオンライン入手可能です。
- The Racket Guide —— 公式ドキュメント群で、最高品質の一つです。
- Beautiful Racket —— 自分だけの言語を構築する方法を学ぶために最適です。
- SICP —— 完全な啓示を求めるなら、まさに古典中の古典です。