見出し画像

関数型プログラミング事始め (15) 配列 - Lisp超入門4

関数型プログラミングがはじめての方へ贈る入門の書
前節:変数と名前 次節:繰り返し
参考書:
・五味 弘「はじめてのLisp関数型プログラミング」技術評論社(2016)
・大山口 通夫、五味 弘「プログラミング言語論」コロナ社(2008)
・五味 弘「関数型プログラミングと数学(ITと数学)」技術評論社(2021)

ISLispの配列、具体的にはベクター(1次元配列)とアレイ(多次元配列)を紹介します。配列は便利で効率的なデータ構造です。要素のアクセスがO(1)でできます。リストがO(n)であるのに対し、非常に効率的です。しかし配列は副作用を積極的に、というよりもメインに利用するものです。このため配列の要素は誰でもどこからでもいつでも変更されてしまい、バグの温床になります。配列は必要悪とは言えませんが、注意して使うことが必要です。しかし恐れずに使うことも必要です。まさに清濁併せ呑むのが大事です。

(7) 配列

Lispには配列のデータ構造が用意されています。1次元配列であるベクター(vector)と多次元配列であるアレイ(array)のデータタイプがあります。ちなみにCommon Lispではベクターはアレイの副型となっています。

まずはislispを起動してください。なおISLisp処理系はLisp処理系の導入で紹介していますので参照してください。

> ISLisp Version 0.80 (1999/02/25)
>
ISLisp>

(a) ベクター vector

ベクターは1次元配列で、以下のように使います。

ISLisp>(defglobal v #(0 1 2 3))   ; #(0 1 2 3)のベクターを初期値にする
V
ISLisp>v
#(0 1 2 3)
ISLisp>(aref v 1)  ; ベクター v の1番目(0番から始まる)の要素を返す
1
ISLisp>(setf (aref v 1) 10) ; ベクター v の1番目に10を格納する
10
ISLisp>v
#(0 10 2 3)  ; 1番目の要素が10になっている
ISLisp>(set-aref 100 v 1)  ; セッター関数による値の格納
100
ISLisp>v
#(0 100 2 3)

関数aref(array reference)で要素にアクセスします。用例は(aref ベクター インデックス)です。なおLispのインデックスは0から始まります(0 origin)。

ベクターにデータを格納するときはsetf(set form)を使います。setfは汎用代入ができるもので(setf アクセス形式 値)で使い、ベクターのアクセス形式は(aref ベクター インデックス)になります。ここはCommon Lispと同じです。

なおISLispではセッター関数も定義されており、配列のセッター関数はset-arefがあります。用例は(set-aref 値 ベクター インデックス)です。

(b) アレイ array

Lispでは多次元配列が扱えます。ベクターのベクターで実装されるジャグ配列でなく、各行の長さが同じであり、アクセスがO(1)で可能な多次元配列が使えます。

ISLisp>(defglobal a #2a((0 1 2) (3 4 5) (6 7 8))) ; 2次元配列を初期値にする
A
ISLisp>a
#2A((0 1 2) (3 4 5) (6 7 8))
ISLisp>(aref a 1 2) ; アレイ a の1行2列の値を返す(0 origin)
5
ISLisp>(setf (aref a 1 2) 50) ; アレイ a の1行2列に50を格納する
50
ISLisp>a
#2A((0 1 2) (3 4 50) (6 7 8))
ISLisp>(set-aref 500 a 1 2) ; セッター関数を使って500を格納する
500
ISLisp>a
#2A((0 1 2) (3 4 500) (6 7 8))

多次元配列は次元数Dのときは、#Da((…(0 1 2 …) …) …)のように記載できます。ベクターは1次元配列なので、#(0 1 2 3)は#1a(0 1 2 3)のように記載できます。逆に#(0 1 2 3)は1次元配列の略記と捉えることもできます。

(c) 文字列 string

文字列は要素が文字であるベクターです。このため、アクセスはベクターと同様にできます。なお文字列特有の関数は後日紹介する予定です。

ISLisp>(defglobal s "abc") ; 文字列"abc"を初期値にする
S
ISLisp>s
"abc"
ISLisp>(setf (aref s 1) #\B) ; 文字列"abc"の1番目の文字を#\B(文字B)にする
#\B
ISLisp>s
"aBc"

上記を見てわかるように、Lispの文字列はミュータブル(変更可能)な型です。Javaなどが文字列をイミュータブル(変更不可)にしているのに対し、自由です。すみません、これは完全に言い訳で、関数型プログラミングの風上にも置けない仕様です。

言い訳の2番目として、文字列の値を動的に変更しないようにしましょう。これはC言語などでも同様に言える弁護、いえ、アドバイスです。

(次回予告)Lisp超入門5

次回もOK! ISLisp処理系を使って、Lispの超入門の第5回を紹介する予定です。お楽しみに。

参考:プログラミング言語はどれがお得?(前編)|五味弘 (note.com)
参考:プログラミング言語はどれがお得?(後編)|五味弘 (note.com)


よろしければサポートをお願いします!