[読書] Land of Lisp – 1

概要

Land of Lisp の1章から3章までの要約です。

背景

一部の層から神の言語として崇拝されているLispを勉強してみました。

要約

1章 さあLispを始めてみよう

Lispには多種の方言があり、メジャーなものとしてCommonLispとSchemeがあります。

言語仕様であり、実装はまた別にあります。CommonLispの実装はCLISP、SBCL、AllegroCommonLispなどがありますが、本書ではCLISPを使います。

CLISPを含むほとんどのCommonLisp環境では、起動すると自動的にread-eval-print-loop(REPL)に入ります。REPLでは直接Lispコマンドを実行することができます。

2章 はじめてのLispプログラム

バイナリサーチ(二分探索)を使った数当てゲームを作る章です。

変数定義などの基礎となる要素が解説されています。

グローバル変数を定義する

Lispではグローバルに定義される変数をトップレベル定義と呼びます。
トップレベル定義は defparameter 関数で作ることができます。

(defparameter *hoge* 0)

Lispのグローバル変数は、変数名の最初と最後にアスタリスク(*)をつける慣習があります。
耳当て(earmuffs)と呼ばれるようで、慣習なので区別しやすくする以外の意味はありません。

グローバル関数を定義する

グローバル関数は defun 関数で作ることができます。

(defun plus-one ()
  (+ *hoge* 1))

plus-oneの後ろの括弧は引数を取らないことを意味します。引数をとる場合はこの括弧の中に書きます。

CommonLispでは、いつも最後に評価された結果を返します。
そのため計算結果をprintするような処理を書かなくとも結果が出力されます。

ローカル変数を定義する

ローカル変数は let 関数で作ることができます。

(let ((a 5)
      (b 6))
  (+ a b))

ローカル変数はlet本体の中でだけ使うことができます。

ローカル関数を定義する

ローカル関数は flet 関数で作ることができます。

(flet ((fun1 (n)
          (+ n 10)
       (fun2 (n)
          (+ n 20)))
  (fun1 (fun2 5)))

ローカル変数と同様にローカル関数はflet本体の中でだけ使うことができます。

3章 Lispの構文の世界を探検する

Lispの構文について解説する章です。

シンタックスとセマンティクス

シンタックスは正しい文を構成するための規則、セマンティクスは文の意味、を表します。

Lispのシンタックスは、括弧を使ってコードをリストにする(リストシンタックス)だけです。

シンボル

シンボルはLispの最も基本的なデータ型です。
CommonLispではシンボルはアルファベット、数字、記号から構成されます。

CommonLispではシンボルの大文字と小文字を区別しません。
ただし、慣習として大文字は使わないようです。

(eq 'fooo 'FoOo) ;大文字と小文字を区別しないので真が返ります

数値

Lispは浮動小数点と整数の両方をサポートしています。

Lispの特徴として他の言語できないような数値計算ができます。

(expt 53 53) ; 53の53乗の計算も正しく計算結果を返します。
(/ 4 6) ; 2/3を計算結果として返します。有理数を表せます。
(/ 4.0 6) ; 0.6666667を返します。計算結果に浮動小数点が含まれると結果も少数になります。

文字列

Lispでの文字列はダブルクォート(“)で囲うことで表せます。

(princ "Tutti Frutti") ; princは表示するためのコマンドです。

エスケープ文字はバックスラッシュです。日本人は普通に”\”を使えばいいです。

(princ "He yelled \"Stop that thief\" from the busy street.")

Lispはコードとデータをどう区別するか

Lispはコードを読み込む際に コードモードデータモード 2つのモードを持っています。

コードモードでは、読み込まれたコードがコンパイラに実行されます。デフォルトはコードモードで処理されます。
データモードでは、コンパイラに実行されずデータとして扱われます。リストの前にシングルクォート(‘)をつけることでデータとして扱うことができます。

(expt 2 10) ; コードモードで実行されるため計算結果の1024が返ります。
'(expt 2 10) ; データモードで実行されるため (expt 2 10) が返ります。

コンスセル

コンスセルは2つのセル(箱)をくっつけたものです。cons関数で作ります。
セルはLispデータを指しても、他のコンスセルを指してもいいです。

(cons 'chiken 'cat) ; (CHIKEN . CAT)というコンスセルが返ります。コンスセルはドットで区切られます。

Lispでのリストはコンスセルによって繋ぎ合わされ、末尾にnilがあるもののことを指します。

‘(1 2 3)のリストをイメージにしたもの
(cons 1 (cons 2 (cons 3 'nil))) ; 末尾がnilなので(1 2 3)というリストが返ります。

CommonLispではシンボルnilと空のリスト()は同じものです。

car関数とcdr関数

コンスセルからデータを取り出すためにはcar関数とcdr関数を使います。

car関数では最初のセルからデータを取り出します。
cdr関数では2番目のセルからデータを取り出します。

(car '(pork beef chiken)) ; 最初のセルのPORKが返ります。
(cdr '(pork beef chiken)) ; 2番目のセルの(beef chiken)が返ります。下の画像のとおり、要素が2つ以上のリストにcdrをするとリストが返ります。
2番目のセルは赤枠の部分を指すのでリストが返る

おまけ

オライリー本の表紙には動物が描かれていることで有名ですが、Land of LispではLispエイリアンが表紙を飾っています。

崇拝されるLisp神

コメント