関数型言語 Lisp

作成日: 2007-06-09
最終更新日:

関数型言語 Lisp

Lisp を少し勉強したのは、バブルまっさかりの頃だった。 そしてバブル崩壊とともにLispも忘れてしまった。 久しぶりに今になって、少し思い出そうとしている。

インストール

Common Lispの処理系として、Vine Linux で apt 化されているのが CLisp だった。 これを apt-get install clisp としてインストールした。

CMUCL のインストール

CLisp をインストールしたあと、まったくLisp の勉強をしなかった。 その後、Vine Linux 4.1 の環境自体がこわれてしまった。 このとき、バックアップをとっていなかったため、データも失われた。 その後、新たに Vine Linux 5.1 を入れた。 新たな処理系としては、CLisp ではなく、CMUCL をインストールした。 これは、ダグ・ホイトの LET OVER LAMNDA で第一に推薦されている処理系である。

起動と終了

起動は単に lisp である。これで、対話式の環境が立ち上がる。

$ lisp
CMU Common Lisp 20a (20A Unicode), running on localhost.localdomain
With core: /usr/local/lib/cmucl/lib/lisp-sse2.core
Dumped on: Tue, 2009-09-29 00:12:34+09:00 on usrtc3154
See <http://www.cons.org/cmucl/> for support information.
Loaded subsystems:
    Unicode 1.5 with Unicode version 5.1.0
    Python 1.1, target Intel x86
    CLOS based on Gerd's PCL 2008-11-12 16:36:41
* 

終了はどうするか、わからなかった。どうやら、次らしい。

* (cl-user::quit)
$

その後 Windows に変わる

その後、Windows が標準環境となった。そこで、CLisp に再度もどした。

2020 年 Lisp のインストール

WSL (Windows Subsytem on Linux) の Ubuntu 20.04 に Steel Bank Common Lisp (SB Common Lisp)をインストールした。 実際には、パッケージ roswell を導入している。インストールは https://qiita.com/t-sin/items/054c2ff315ec3b9d3bdc の通り行った。

$ sudo apt update
$ sudo apt install git build-essential automake libcurl4-openssl-dev
$ git clone https://github.com/roswell/roswell
$ cd roswell
$ ./bootstrap && ./configure && make
$ sudo make install
$ ros setup

動かしてみる。

$ ros run
* (format t "Hello World!~%")
Hello World!
nil
* (quit)
$

なお、foo.lispという名称の Lisp ソースファイルをロードするときは、
(load "foo.lisp")
とする。

cmu-lisp を入れる

sbcl はいい処理系なのだろうが、Let Over Lambda の例が一部動かないので困った。 そこで日和見して cmu-lisp も入れることにした。

$ ros install cmu-bin
Checking version to install...
Downloading https://common-lisp.net/project/cmucl/downloads/release/
[##########################################################################]100%
Installing cmu-bin/21d...
Downloading https://common-lisp.net/project/cmucl/downloads/release/21d/cmucl-21d-x86-linux.tar.bz2
[##########################################################################]100%
Downloading archive:https://common-lisp.net/project/cmucl/downloads/release/21d/cmucl-21d-x86-linux.tar.bz2:OK
Downloading https://common-lisp.net/project/cmucl/downloads/release/21d/cmucl-21d-x86-linux.extra.tar.bz2
[##########################################################################]100%
Downloading archive:https://common-lisp.net/project/cmucl/downloads/release/21d/cmucl-21d-x86-linux.extra.tar.bz2:OK

Extracting archive:/home/username/.roswell/archives/cmucl-21d-x86-linux.tar.bz2

Extracting archive:/home/username/.roswell/archives/cmucl-21d-x86-linux.tar.bz2
$ ros use cmu-bin
/home/username/.roswell/impls/x86-64/linux/cmu-bin/21d/bin/lisp: 1: Syntax error: Bad function name
Error: unable to use 'cmu-bin'

残念。いま調べてわかったのだが、CMU Common Lisp はまだ 32 ビットなので、64 ビットには対応していなかったのだ。 代わりに ccl をインストールしてみる。

$ ros install ccl-bin
Checking version to install...
Downloading https://github.com/roswell/ccl_bin/releases.atom
[##########################################################################]100%
Installing ccl-bin/1.12...
Downloading https://github.com/roswell/ccl_bin/releases/download/1.12/ccl-1.12-linuxx86.tar.gz
[##########################################################################]100%
Downloading archive:https://github.com/roswell/ccl_bin/releases/download/1.12/ccl-1.12-linuxx86.tar.gz:OK

Extracting archive:/home/username/.roswell/archives/ccl-1.12-linuxx86.tar.gz
$ ros use ccl-bin

あれ?プロンプトが返ってこない。ctrl-c で強制終了させると、こんな表示がされた。

^CUnhandled SB-SYS:INTERACTIVE-INTERRUPT in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                                    {10032E8103}>:
  Interactive interrupt at #x7FA2CEE05AC7.

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10032E8103}>
0: ("bogus stack frame")
1: (SB-IMPL::SUB-SERVE-EVENT 10 0 NIL)
2: (SB-SYS:SERVE-ALL-EVENTS 10)
3: (SB-EXT:PROCESS-WAIT #<SB-IMPL::PROCESS 637 :RUNNING> NIL)
(後略)

どうしたんだろう。

(base) $ ros run
Unhandled exception 11 at 0x300000c47d2b, context->regs at #x7fffc28a27c8
received signal 11; faulting address: (nil)
unexpected si_code value: 128
? for help
[641] Clozure CL kernel debugger: 	

いきなりデバッガモードになる。これでは使えないよう!

そのほか、Clozure CL を何度も試したが、必ず Unhandled exception から始まるデバッグモードに入ってしまい、 どうしても動かない。あきらめた。

数値計算と再帰関数

LISP のような関数型言語と相性がいいのが再帰計算だろう。副作用を排除して複数のデータを扱う関数が再帰関数である。 再帰関数の例としては、自然数の和やべキ乗、そして階乗の計算が多い。 あるいは、データ構造が再帰的であるリストの処理も例題としてよく使われている。 さて、繰り返しのあるところには再帰関数があると言われている。それならば、もっと再帰関数で書かれるべき計算があるはずだ。 たとえば、数値計算である。ニュートン法など、ピッタリの題材ではないか。 そう思っていたが、数値計算、特に浮動小数点の計算を伴う数値計算と再帰関数をからめた記述はほとんど見当たらない。 探していて最初に見つかったのが、あの SICP (計算機プログラムの構造と解釈)の 1.1.7 項 「Newton法による平方根」である。 これは Scheme で書かれているが、LISP に翻訳してみたので観察する。 この関数は SICP の初期バージョンに基づく。このバージョンの欠点は後述する。

	;; guess * guess が x と近くなるまで逐次計算 -- 改良 improve -- する
	;; sqrt-iter が再帰的に定義されていることを確認する。
	:: 同時に 終了条件 good-enough? が満足されている(数値計算法により満たされている)
	(defun sqrt-iter (guess x)
      (if (good-enough? guess x)
        guess
        (sqrt-iter (improve guess x)
				 x)))

	;; ニュートン法により、逐次近似は guess_(n+1) ← x / guess_n で与えられる 
	(defun improve (guess x)
      (average guess (/ x guess)))

	;; 2数の平均 average の定義。
	  (defun average (x y)
		(/ (+ x y) 2.0) )
	
	;; 二乗の定義。SB Common Lisp には定義されていないのでここで定義する
	(defun square (x)
	  (* x x) )

	;; 「十分よい近似」のもっともらしい考え方 guess * guess と x の絶対値の差が一定値以下
	(defun good-enough? (guess x)
	(< (abs (- (square guess) x)) 0.001))

	;; 開始の方法。初期値は x の値にかかわらず 一律に 1.0 としてもほぼ収束する。
	;; sqrt(x) は SB Common Lisp に定義されているので、my- をつけた
	(defun my-sqrt (x)
		 (sqrt-iter 1.0 x))

このバージョンの欠点は次のとおりである。

これらの欠点の解消方法も、SICP には示されている。

リンク

参考書

まりんきょ学問所関数型言語手習い > 関数型言語 Lisp


MARUYAMA Satosi