ベクタの作成
ベクタ定数
この式は
datum を成分とするベクタを作ります.
datum は何でも指定できます.ただし,次の点に注意して下さい.
-
ベクタ定数は self-evaluating なので,式の先頭にクォート(')を付けたり,
qoute 式で囲む必要はありません.
- datum は評価されません.self-evaluating な datum(ブール値,数値,文字,文字列,ベクタ,バイトベクタ) は,それが表現するデータとして処理され,self-evaluating でない datum はシンボルやリストとして処理されます.
-
ベクタ定数は変更不可能(immutable)です.各成分の値は変更できません.
具体例
以下の1番目の式は,
数値(10と20),文字(#\a と #\b),文字列("Guile"),シンボル(Scheme)からなるベクタ定数を作っています.2番目の式は数値リスト定数,文字列リスト定数,シンボルリスト定数からなるベクタ定数を作っています.
guile> #(10 20 #\a #\b "Guile" Scheme)
$1 = #(10 20 #\a #\b "Guile" Scheme)
guile> #((1 2 3) ("a" "b" "c") (a b c))
$2 = #((1 2 3) ("a" "b" "c") (a b c))
なお,'Scheme といったようにシンボルにクォート(')をつけると,
以下に示すようにクォート(quote)もデータの一部になってしまいます.
リスト定数の場合と同様に,ベクタの成分は評価されないので,
各成分にクォートを付ける必要はありません.
guile> #(10 20 #\a #\b "Guile" 'Scheme)
$3 = #(10 20 #\a #\b "Guile" (quote Scheme))
ベクタ定数の各成分(
datum )は評価されません.
例えば,以下の算術式は評価されることはなく,
シンボルとしての演算記号,シンボルとしての変数記号(x と y),数値定数からなるリスト定数として処理されます.
guile> #((+ x 20) (- 10 y) (* 10 20))
$4 = #((+ x 20) (- 10 y) (* 10 20))
ベクタ定数(によって生成したベクタデータ)は変更不可能(immutable)なので,
その成分を変更しようとするとエラーが発生します.以下の実行例では,10,20,30 の3つの成分からなるベクタ定数の第0成分(先頭の成分)を vector-set! を使って 99 に変更しようとして,エラーが発生しています.
guile> (define vec #(10 20 30))
guile> vec
$1 = #(10 20 30)
guile> (vector-set! vec 0 99)
In procedure vector-set!: Wrong type argument in position 1 (expecting mutable vector): #(10 20 30)
vector ― 要素を指定して作る
procedure:
(vector obj ... )
この手続きは,
obj ... からなるベクタを作って返します.
vector 手続きによって作成したベクタは変更可能(mutable)です.
つまり,各成分の値を変更することができます.
具体例
guile> (vector 1 2 3)
$1 = #(1 2 3)
guile> (vector 10 #\a "Guile" 'Scheme)
$2 = #(10 #\a "Guile" Scheme)
guile> (vector (+ 10 20) (- 10 20) (* 10 20))
$3 = #(30 -10 200)
vector 手続きで生成したベクタは変更可能(mutable)なので,
その成分を変更しようとしてもエラーにはなりません.
以下の実行例は,ベクタ定数の実行例の中でエラーが発生した変更操作を行っています.
guile> (define vec (vector 10 20 30))
guile> vec
$1 = #(10 20 30)
guile> (vector-set! vec 0 99)
guile> vec
$2 = #(99 20 30)
make-vector ― 長さを指定して作る
procedure:
(make-vector len)
(make-vector len obj)
len |
長さ(成分数)を表す整数値 |
obj |
オブジェクト |
返り値 |
ベクタ |
この手続きは,
len で指定された長さ(成分数)のベクトルを作って返します.
obj を指定した場合,各成分を
obj に初期設定します.
obj を省略した場合,各成分の値は unspecified です.
この手続きで作成したベクタは変更可能(mutable)です.
具体例
guile> (make-vector 3)
$1 = #(#<unspecified> #<unspecified> #<unspecified>)
guile> (make-vector 5 0)
$2 = #(0 0 0 0 0)
list <--> vector ― リストとベクタの相互変換
procedure:
(list->vector lst)
(vector->list vec)
lst |
リスト |
vec |
ベクタ |
返り値 |
list->vector はベクタを返し,vector->list はリストを返す. |
list->vector はリスト(
lst)をベクタに変換して返します.
逆に,vector->list はベクタ(
vec)をリストに変換して返します.
返り値のベクタやリストは変更可能(mutable)です.
具体例
guile> (list->vector '(10 20 30))
$1 = #(10 20 30)
guile> (vector->list #(10 20 30))
$2 = (10 20 30)
補足
(srfi srfi-43) モジュールをロードすると,機能拡張された同名の手続きを使うことができます.その手続きは,変換対象の部分列が指定できるようになっています.
ベクタの操作
vector? ― ベクタ型の検査
これは,
obj がベクタならば #t を返し,
そうでなければ #f を返します.
具体例
guile> (vector? #(10 20 30))
$1 = #t
guile> (vector? '(10 20 30))
$2 = #f
vector-length ― ベクタの長さ(成分数)
procedure:
(vector-length vec)
これは
vec の長さ(成分数)を返します.
具体例
guile> (vector-length #(10 20))
$1 = 2
guile> (vector-length #(10 20 30))
$2 = 3
guile> (vector-length #(10 20 30 40))
$3 = 4
vector-ref ― 成分の抽出
procedure:
(vector-ref vec idx)
vec |
ベクタ |
idx |
添字(成分の番号) |
返り値 |
成分の値 |
これは
vec の
idx 番目の成分を返します.
次の点に注意して下さい.
-
最初の成分の添字は 0 で,
vecの長さを $\ell$ とするとき,
最後の成分の添字は $\ell-1$ です.
この範囲以外の添字を指定したときにはエラーが発生します.
具体例
guile> (vector-ref #(10 20 30 40) 0)
$1 = 10
guile> (vector-ref #(10 20 30 40) 1)
$2 = 20
guile> (vector-ref #(10 20 30 40) 2)
$3 = 30
guile> (vector-ref #(10 20 30 40) 3)
$4 = 40
ベクタの長さを $\ell$ とするとき,添字(
idx)は
$0 \leq$
idx $\leq \ell-1$ を満たさなければいけません.
この範囲以外の添字を指定したときにはエラーが発生します.
guile> (vector-ref #(10 20 30 40) 4)
In procedure vector-ref: Argument 2 out of range: 4
vector-set! ― 成分の変更
procedure:
(vector-set! vec idx obj)
vec |
ベクタ |
idx |
添字(成分の番号) |
obj |
オブジェクト |
返り値 |
unspecified |
これは,ベクタ(
vec)の
idx 番目の成分を
obj に変更します.次の点に注意して下さい.
具体例
guile> (define vec (make-vector 4 'x))
guile> vec
$1 = #(x x x x)
guile> (vector-set! vec 0 'A)
guile> vec
$2 = #(A x x x)
guile> (vector-set! vec 2 (+ 10 20))
guile> vec
$3 = #(A x 30 x)
ベクタが変更可能(mutable)でないときエラーが発生します.
guile> (define vec #(x x x x))
guile> vec
$1 = #(x x x x)
guile> (vector-set! vec 0 'A)
In procedure vector-set!: Wrong type argument in position 1 (expecting mutable vector): #(x x x x)
vector-fill! ― 全成分の変更
procedure:
(vector-fill! vec obj)
(vector-fill! vec obj start)
(vector-fill! vec obj start end)
vec |
ベクタ |
obj |
オブジェクト |
start |
変更を開始する位置.省略時は0に設定される. |
end |
変更を終了する位置.省略時はベクタ(vec)の長さに設定される. |
返り値 |
unspecified |
これは,ベクタ(
vec)の
start 番目から
end$\,-1$ 番目までの成分を
obj に変更します.これら以外の成分は変更しません.
start を省略したときには 0 に設定されます.
end を省略したときにはベクタ(
vec)の長さ(成分数)に設定されます.
次の点に注意して下さい.
具体例
guile> (define vec (make-vector 4 'x))
guile> vec
$1 = #(x x x x)
guile> (vector-fill! vec 'A)
guile> vec
$2 = #(A A A A)
guile> (vector-fill! vec (+ 10 20) 1 3)
guile> vec
$3 = #(A 30 30 A)
start $=$
end の場合,何も変更しません.
guile> (vector-fill! vec 'Guile 0 0)
guile> vec
$4 = #(A 30 30 A)
guile> (vector-fill! vec 'Guile 1 1)
guile> vec
$5 = #(A 30 30 A)
start(と
end)が成分数の場合でもエラーは発生しません.
guile> (vector-fill! vec 'Guile 4)
guile> vec
$6 = #(A 30 30 A)
guile> (vector-fill! vec 'Guile 4 4)
guile> vec
$7 = #(A 30 30 A)
vector-copy ― ベクタのコピー
procedure:
(vector-copy vec)
(vector-copy vec start)
(vector-copy vec start end)
vec |
ベクタ |
start |
コピーを開始する位置.省略時は0に設定される. |
end |
コピーを終了する位置.省略時はベクタ(vec)の長さに設定される. |
返り値 |
ベクタ |
注意
-
Debian 11のパッケージが提供する Guile 3.0.5 では,start と end は指定できません.start と end が指定可能な手続きは Guile 3.0.8 になってコアシステムに組み込まれたようです.Guile 3.0.7 以前では,それは (srfi srfi-43) モジュールの中で定義されています.従って,それを使うには同モジュールをロードする必要があります.
ベクタ(
vec)の
start 番目から
end$\,-1$ 番目までの成分からなるベクタを新たに作成して返します.
start を省略したときには 0 に設定されます.
end を省略したときにはベクタ(
vec)の長さ(成分数)に設定されます.
次の点に注意して下さい.
具体例
以下では,変更不可能(immutable)なベクタ(vec1)を定義して,そのコピー(vec2)を作っています.さらに,vec1 と vec2 が異なるオブジェクトであることを(適当に)確認しています.
guile> (define vec1 #(10 20 30 40))
guile> vec1
$1 = #(10 20 30 40)
guile> (define vec2 (vector-copy vec1))
guile> vec2
$2 = #(10 20 30 40)
guile> (vector-set! vec2 0 99)
guile> vec2
$3 = #(99 20 30 40)
guile> vec1
$4 = #(10 20 30 40)
Guile 3.0.7 以前では,(srfi srfi-43) モジュールをロードすれば
start や
end も指定できる手続きが使えます.
guile> (use-modules (srfi srfi-43))
guile> (define vec #(0 10 20 30 40 50))
guile> vec
$1 = #(0 10 20 30 40 50)
guile> (vector-copy vec 2 5)
$2 = #(20 30 40)
end がベクタ(
vec)の長さより大きい場合,
エラーは発生せずに
start$\,-\,$
end の長さのベクタが生成され,コピー元から必要なコピーを行った残りの成分は unspecified になります.
guile> (vector-copy vec 3 10)
$3 = #(30 40 50 #<unspecified> #<unspecified> #<unspecified> #<unspecified>)
start $=$
end だったり,
start がベクタの長さだった場合,空ベクタが作成されます.
guile> (vector-copy vec 2 2)
$4 = #()
guile> (vector-copy vec 6 6)
$5 = #()
guile> (vector-copy vec 6)
$6 = #()
参考
Guile 3.0.7 以前では,この手続きは (srfi srfi-43) モジュールの中で次のように定義されています.以下の guile-vector-copy はコアモジュールのコピー手続きです.それから,vector-move-left! はコアモジュールが提供する別種のコピー手続きです.これについては後述する説明を参照して下さい.
(define vector-copy
(case-lambda*
((v) (guile-vector-copy v))
((v start)
(assert-vector v 'vector-copy)
(let ((len (vector-length v)))
(assert-valid-start start len 'vector-copy)
(let ((result (make-vector (- len start))))
(vector-move-left! v start len result 0)
result)))
((v start end #:optional (fill *unspecified*))
(assert-vector v 'vector-copy)
(let ((len (vector-length v)))
(unless (and (exact-integer? start)
(exact-integer? end)
(<= 0 start end))
(error-from 'vector-copy "invalid index range" start end))
(let ((result (make-vector (- end start) fill)))
(vector-move-left! v start (min end len) result 0)
result)))))
この定義を見ると,
end がベクタ(
vec)の長さより大きい場合の unspcified をオプション引数として任意の値に設定できるようです.実際,次のようになります.
guile> (vector-copy vec 3 10 'X)
$7 = #(30 40 50 X X X X)
補足
Guile[6.6.10.3 Accessing and Modifying Vector Contents]
によれば,Guile 3.0.8 のコアモジュールが提供する vector-copy は上述のオプション引数を指定できません.従って,Guile 3.0.8 でも,オプション引数を指定したい場合には (srfi srfi-43) モジュールをロードする必要があります.
vector-copy! ― ベクタの転写
procedure:
(vector-copy! dst at src)
(vector-copy! dst at src start)
(vector-copy! dst at src start end)
dst |
ベクタ |
at |
ベクタ(dst)の添字.コピーを保存する先頭の位置. |
src |
ベクタ |
start |
ベクタ(src)の添字.コピ―を開始する位置.省略時は0に設定される. |
end |
ベクタ(src)の添字.コピーを終了する位置.省略時はベクタ(src)の長さに設定される. |
返り値 |
unspecified |
注意
-
この手続きは Guile 3.0.8 になってコアシステムに組み込まれたようです.
Guile 3.0.7 以前では,この手続きは (srfi srfi-43) モジュールの中で定義されています.従って,これを使うには同モジュールをロードする必要があります.
これは,コピー元のベクタ(
src)の
start 番目から
end$\,-1$ 番目までの成分を,コピー先のベクタ(
dst)の
at 番目以降の成分に保存(転写)します.次の点に注意して下さい.
補足
この手続きはライブラリ関数の memmove を使って実装しています.カーネルソースの中にある memmove 関数のソースコードを見ると,上で述べたような余計な作業領域を使用しません.上記の説明はあくまで便宜的なものです.
具体例
Guile 3.0.7 以前では,(srfi srfi-43) モジュールをロードすれば vector-copy! 手続きが使えます.
以下では,1つのベクタ(vec)の中で,2番目から5番目の成分(下記の20,30,40,50)を左側(1番目以降の成分)にコピー(転写)する場合を実行してみます.
guile> (use-modules (srfi srfi-43))
guile> (define vec (vector 0 10 20 30 40 50 60 70))
guile> vec
$1 = #(0 10 20 30 40 50 60 70)
guile> (vector-copy! vec 1 vec 2 6)
guile> vec
$2 = #(0 20 30 40 50 50 60 70)
今度は1番目から4番目の成分(下記の10,20,30,40)を右側(2番目以降の成分)にコピー(転写)する場合を実行してみます.
guile> (define vec (vector 0 10 20 30 40 50 60 70))
guile> vec
$3 = #(0 10 20 30 40 50 60 70)
guile> (vector-copy! vec 2 vec 1 5)
guile> vec
$4 = #(0 10 10 20 30 40 60 70)
vector-move-{left!,right!} ― ベクタの転写
procedure:
(vector-move-left! vec1 start1 end1 vec2 start2)
(vector-move-right! vec1 start1 end1 vec2 start2)
vec1 |
ベクタ |
start1 |
ベクタ(vec1)の添字.コピ―を開始する位置. |
end1 |
ベクタ(vec1)の添字.コピーを終了する位置. |
vec2 |
ベクタ |
start2 |
ベクタ(vec2)の添字.コピーを保存する先頭の位置. |
返り値 |
unspecified |
これらは,
コピー元のベクタ(
vec1)の
start1 番目から
end1$\,-1$ 番目までの成分を,コピー先のベクタ(
vec2)の
start2 番目以降の成分に保存(転写)します.
vector-move-left! は,
vec1 の添字の小さいほうから順に(直観的に言うと,左側の成分から順に)コピーします.vector-move-right! は,
vec1 の添字の大きいほうから順に(直感的に言うと,右側の成分から順に)コピーします.これらの違いが影響するのは,
vec1 と
vec2 が同じ場合です.2つのベクタが異なる場合には,どちらを使っても結果は同じです.
次の点に注意して下さい.
具体例
コピー元とコピー先が同じベクタの場合にコピーがどのように行われるかを試してみます.
以下では,ベクタ vec を適当に作って,vector-move-left! を使って,vec[2]〜vec[5] を vec[0]〜vec[3] にコピーしてみます.これは
vec[2] $\rightarrow$ vec[0],
vec[3] $\rightarrow$ vec[1],
vec[4] $\rightarrow$ vec[2],
vec[5] $\rightarrow$ vec[3]
の順にコピーを行います.以下の実行例を見ると,vec[2]〜vec[5] の値である 20〜50 がそのまま vec[0]〜vec[3] にコピーされています.
guile> (define vec (vector 0 10 20 30 40 50 60 70))
guile> vec
$1 = #(0 10 20 30 40 50 60 70)
guile> (vector-move-left! vec 2 6 vec 0)
guile> vec
$2 = #(20 30 40 50 40 50 60 70)
guile>
次に,ベクタ vec を作り直したあと,vector-move-left! を使って vec[2]〜vec[5] を vec[4]〜vec[7] にコピーしてみます.これは
vec[2] $\rightarrow$ vec[4],
vec[3] $\rightarrow$ vec[5],
vec[4] $\rightarrow$ vec[6],
vec[5] $\rightarrow$ vec[7]
の順にコピーを行います.
guile> (define vec (vector 0 10 20 30 40 50 60 70))
guile> vec
$1 = #(0 10 20 30 40 50 60 70)
guile> (vector-move-left! vec 2 6 vec 4)
guile> vec
$2 = #(0 10 20 30 20 30 20 30)
この結果を見ると,vec[4] $\rightarrow$ vec[6],vec[5] $\rightarrow$ vec[7] のコピーを行うときの vec[4] と vec[5] はコピー後の値が使われていることが分かります.
補足
1つのベクタに対して vector-move-left! を使ってコピーする場合で,
コピー元とコピー先の成分が重なっていて,コピー先がコピー元より右側にある場合,
重なっている成分に関してコピー後の値が再びコピーされます.一方,
コピー先がコピー元より左側にある場合にはコピー後の値が再びコピーされることはありません.
このことは vector-move-right! についても同じが言えます.つまり,
1つのベクタに対して vector-move-right! を使ってコピーする場合で,
コピー元とコピー先の成分が重なっていて,コピー先がコピー元より左側にある場合,
重なっている成分に関してコピー後の値が再びコピーされます.一方,
コピー先がコピー元より右側にある場合にはコピー後の値が再びコピーされることはありません.
以上から,1つのベクタの中でコピー(転写)を行う場合,
左側にコピーするときには vector-move-left! を使い,
右側にコピーするときには vector-move-right! を使うのが一般的と言えます.
「left」と「right」はコピーする方向を示していると言ってもよいでしょう.
でも,vector-copy! を使えば「正しく」コピーできるので,
これらの手続きを使うことはないように感じます.