Common Lisp を触る
目次
はじめに
この記事は Common Lisp で勉強した内容の備忘録です。 大学の言語系の人工知能の講義の資料にあったコードが Lisp で書かれていて、それをきっかけに Lisp に興味を持ち、勉強してみることにしました。 Lisp には方言と呼ばれる、処理系が複数存在して、その中でも現在で広く使われている方言である Common Lisp を触っていきます。 この記事を書くにあたって、主に Land of Lisp を読んで勉強しました。 環境は Windows です。
環境構築
Roswell をインストール
Land of Lisp では CLISP をインストールしているのですが、筆者は Roswell から処理系をインストールしました。
CLISP インストーラのダウンロードはこちら (opens new window)
Roswell は Common Lisp 環境のセットアップユーティリティです。 Lisp 処理系やライブラリのインストールのほかに、プログラムをコンパイルし、バイナルファイルにパッケージングすることもできるようです。
Installation - roswell wiki (opens new window) にインストール方法が載っています。
最新のリリースノートから、自分の環境にあったものをダウンロードし、Pathを通しました。
セットアップ
以下のコマンドを叩いてセットアップします。
ros setup
他の ros
コマンドを叩いても、処理系が不足している場合は、セットアップを行ってくれるようです。
Roswell のセットアップでは Steel Bank Common Lisp(SBCL)がインストールされます。
Lisp を起動する
コマンドで ros run
を打つと、デフォルトの処理系が起動します。
ros run
*
SBCL では「*」がプロンプトとなります。 起動すると自動的に read-eval-print ループ(REPL)に入ります。
REPL (Read-Eval-Print Loop) とは、入力・評価・出力のループのこと。インタプリタにおいて、ユーザーとインタプリタが対話的にコード片を実行できるもの。
と Wikipedia に書いてありました。 REPL のことをインタプリタだと勘違いしていたのですが、インタプリタが一連のループを行うことを指すようです。
ここでは、Lisp コードを直にタイプすることができます。 試しに足し算を行ってみます。
ros run
* (+ 1 2)
3
*
Lisp は 1+2 を (+ 1 2)のように関数を前に書く前置記法 (prefix notation)です。 私たちが使い慣れている、1+2 のような、引数と引数の間に演算子を置く記法は、中置記法(infix notation)です。
終了するには以下のようにタイプします。
* (quit)
Roswell からスクリプトを実行する
main 関数を作ると、Roswell からスクリプトを実行することができます。
Hello world! を表示するスクリプト「hello.lisp」を書きます。
(defun main ()
(write-line "Hello world!"))
これを実行します。
ros hello.lisp
Hello world!
Hello world! が表示されました。
データ構造
アトム
シンボルや数値、文字列などリストではないデータのことです。
シンボル
シンボルは、Lisp の最も基本的なデータ型です。
Common Lisp のシンボルは大文字小文字を区別しません。 シンボル同士の比較は eq で行います。
* (eq 'AAA 'aaA)
T
数値
下記などの型があります。
- 整数
- 分数
- 少数
- 複素数
整数どうしの除算では、少数ではなく分数で返ってきます。
* (/ 2 3)
2/3
* (/ 2.0 3)
0.6666667
文字列
ダブルクオートでかこみます。文字列の表示には、princ を使います。
* (princ "Hello!")
Hello!
"Hello!"
リスト
データを要素とする列型のデータのことで、(A B C)
のように括弧で要素を囲みます。
* (list 'a 'b 'c)
(A B C)
list 関数でリストを定義することができます。
* (car (list 'a 'b 'c))
A
* (cdr (list 'a 'b 'c))
(B C)
car 関数を使うとリストの最初の要素を取り出すことができ、cdr 関数を使うとリストの残りの部分を取り出すことができます。
モード
Coomon Lisp にはコードモードとデータモードという 2 つのモードがあります。
コードモード
Lisp はデフォルトではコードモードになっています。
コードはフォームと呼ばれる構造のリストである必要があります。 フォームとは先頭の要素がコマンド(多くの場合は関数名)であるリストのことです。 フォームを読む際には、コマンドの後ろの要素は関数の引数として扱われます。
* (expt 2 10)
1024
上の例では 2 の 10 乗を計算しています。リストの最初の要素である、expt を読み取った際に累乗を計算するコマンドだと認識しています。残りの要素は関数の引数として渡されます。
データモード
コードモードとは違い、データモードではコードはデータとして扱われ、コンピュータは実行しようとしません。
* '(expt 2 10)
(EXPT 2 10)
リストの前に '(シングルクオート)をつけることでデータモードになり、リストをデータとして扱います。この操作のことを「クオートする」とよびます。
関数定義と比較関数、四則演算など
関数定義 defun
* (defun print-hello () (print 'Hello))
PRINT-HELLO
* (print-hello)
HELLO
HELLO
四則演算
* (+ (- 2 1) (/ 4.0 2) (* 2 4))
11.0
絶対値関数 abs
* (abs -3)
3
比較関数
* (<= 8 3)
NIL