世界を動かす技術を、日本語で。

Racketの友好的な入門書

概要

  • Lisp は歴史あるプログラミング言語で、独自の特徴を持つ
  • Racketは Lisp系言語 の現代的進化形で教育や研究に活用
  • コードとデータが同じ構造( ホモアイコニシティ
  • 関数型・再帰・高階関数・マクロなど 強力な抽象化
  • DrRacketを使い 実際に手を動かして学ぶ体験 ができる

Lisp入門:歴史と特徴

  • Lisp は1958年、MITの John McCarthy によって発明
    • 現存する高級言語で Fortran に次いで2番目に古い
  • ガーベジコレクション第一級関数REPL条件式の値返却 など多くの現代的概念を最初に導入
  • コード=データ( ホモアイコニシティ)という思想
  • 1970~80年代はAI研究の中心言語、 Lispマシン も登場
  • AI冬の到来で主流から外れるも、強い影響力を持ち続ける

LispからScheme、Racketへ

  • 1975年、 Gerald SussmanGuy SteeleScheme を開発

    • ミニマルで数学的な美しさ
    • 教育分野で広く採用(代表的な書籍: SICP
  • 1995年、 PLT Scheme (現 Racket)誕生

    • 教育と言語研究向けに設計
    • 2010年に Racket へ改名
    • Language-oriented programming :独自言語を簡単に作成可能
    年表
      • 1958: Lisp誕生
      • 1975: Scheme誕生
      • 1984: Common Lisp標準化
      • 1995: PLT Scheme誕生
      • 2007: Clojure誕生
      • 2010: Racketへ改名
    

現在のLisp活用例

  • Clojure :銀行や航空、スタートアップで本番運用
  • Common Lisp :専門システムや科学計算分野
  • Emacs Lisp :多くのユーザーが日常的に利用(エディタEmacs)
  • Guile/Guix :SchemeベースのLinuxディストリビューション
  • Racket :年次カンファレンス、研究・教育・芸術分野で活用
  • 新しいLisp系 :Fennel(Lua向け)、Janet、Hy(Python上)など

Racketのインストールと基本操作

  • https://racket-lang.org からインストーラーをダウンロード
  • DrRacket (統合開発環境)を起動
    • 上部:プログラム定義エリア
    • 下部: REPL (対話型実行環境)
  • 最初の1行に #lang racket を記述
  • ターミナル派は racket コマンドでREPL起動、raco でパッケージ管理
  • 基本式例
    > (+ 1 2)           ; => 3
    > (* 3 (+ 2 2))     ; => 12
    > (string-append "hello " "world") ; => "hello world"
    
  • すべての構文は (演算子 引数1 引数2 ...) の形

定義・関数・コメント

  • 定数定義:(define pi-approx 3.14159)
  • 関数定義:(define (circle-area r) (* pi-approx r r))
  • コメントは ; から行末まで
  • 無名関数:(lambda (x) (* x x))
  • 直接適用例:((lambda (x) (* x x)) 5) ; => 25

リスト処理:Lispの心臓部

  • リスト生成:(list 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
  • クォート ' は「評価せずデータとして扱う」印

高階関数による抽象化

  • 関数を引数に取る例
    • 変換:(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
  • ループ不要、3つで多くのリスト処理を網羅

再帰的思考

  • 「N回繰り返す」より「基本ケースと再帰的進行」
  • 階乗関数例
    (define (factorial n)
      (if (= n 0) 1
          (* n (factorial (- n 1)))))
    (factorial 5) ; => 120
    

グラフィック描画例

  • Racketには 2htdp/image などのグラフィックライブラリが付属
  • シェルピンスキーの三角形描画例
    #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)
    

コードがデータ:ホモアイコニシティとマクロ

  • クォート ' で「コードをデータ」に変換
    • '( + 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 :Racket設計思想の基礎書(無料公開)
  • The Racket Guide :公式ドキュメント
  • Beautiful Racket :独自言語構築の入門書
  • SICP :Schemeによるプログラミングの古典的名著

Lisp/Racket は「抽象化」「拡張性」「思考法」において他の言語と一線を画す プログラム=データ構造 という発想が、柔軟な言語設計と創造性を支える

Hackerたちの意見

「アメイジング・デジタル・サーカス」(エピソード8、「hjsakldfhl」)で、キングがターミナルを開いてケインをリセットしようとするシーンで、ケイン(1996年に作られたクリエイティブAI)がLispでプログラムされているのがわかるよ。ファイル名はまさにCaine-core.lispだし、いい感じだね。エピソード9でケインが戻ってくる理由も説明されてる。Lispの継続がエラー回復をスムーズにしてくれるんだ。

ケインはCommon Lispで書かれてたんじゃなかったっけ?コマンドラインで使ってたデバッガーがgdbだったのも見たし(それって実際に可能なのかな?)

Racketのファンではあるけど、これはフレンドリーなイントロじゃないね。スピードランみたいだ。イントロが「フレンドリー」って言うなら、ラムダが何か知ってる前提で進めるのはやめてほしい。イントロで「フレンドリー」って言うなら、構文ルールが出てくるのは全然期待してないよ。

情報が豊富で、要点がしっかりしてて、やる気があって有能な読者がすぐにRacketについて知識を得て役立てられるように提示されてる。少なくとも、これを読む前はRacketについて何も知らなかった私にはそうだったよ。プログラミング言語のイントロで構文ルールが含まれてないって、どういうこと?私たちはみんな情報を持っていて、経験豊富で、テクノロジーに興味がある人たちだよ。バカな子供じゃないんだから。君のコメントがただの反対意見の戯言にしか見えないのが辛い。

「フレンドリーなイントロ」って見ると、真ん中にデッドヘッドのステッカーがあるのは期待してないんだけど、実際にデッドヘッドなら驚かないのかな。 ;-)

頭蓋骨のことは言わずもがなだけど、グレイトフル・デッドのロゴを模倣するのって、ラケットの特徴なの?それともLisp全般のこと?

言語自体は面白いけど、残念ながら実際には誰も使ってないね。もしかしたら、デプロイの選択肢が面倒だからかも?ネイティブのスタンドアロン実行ファイルを作れるようになれば、もっと使われると思うんだけど。

Racketはしばらく前からスタンドアロン実行ファイルを作れるようになってるよ。

https://docs.racket-lang.org/guide/exe.html

たくさんの人が実際に使ってるから、どこからその情報を得たのかは分からないな。

自分でRacketでAIコーディングハーネスを作ったんだけど、ちゃんと動いてるし、自分のニーズにも合ってる。前のバージョンはCommon LispとPythonで作ったけど、Racketのやつが一番機能が充実してるね。

特に特別な構文はないね。(list '(1. . ##) -5/6+7.s-8i `(1 ,@2) 1@1 ;うーん、アンコートスプライシングカンマはないね ;-) 10# ;驚いた? (list #i+1 +1i 1+i) ;複雑? #e-1e10i ;オールドマクドナルド? "(* 9 10)" #()

Hacker Newsで議論の続きを見る