ベクタは固定長でO(1)アクセス可能な値の並びです。 Schemeは伝統的に、任意の値を格納できるベクタを提供してきました。 これはベクタで説明されます。
R7RS-largeでは、均質な数値型だけを効率よく格納できるベクタ(uvector)も定義されています。 ユニフォームベクタを見てください。
Gaucheはまた、ビット列を格納するビットベクタも提供します。 ビットベクタで説明します。
最後に、weakベクタは任意の要素をweakポインタを使って格納できるベクタです。 Weakベクタ参照。
• ベクタ | ||
• ユニフォームベクタ | ||
• ビットベクタ | ||
• Weakベクタ |
ベクタはSchemeオブジェクトの単純な一次元配列です。 インデックスを用いて定数時間でその要素にアクセスできます。 一度作成されたベクタはその大きさを変えることはできません。
<vector>
クラスはまた<sequence>
クラスを継承し、
map
やfold
など様々な総称関数を使うことができます。
コレクションフレームワーク と
シーケンスフレームワーク を参照して下さい。
数値しか要素に持たないベクタを使う場合、SRFI-4の 単一型ベクタも使えるかもしれません (単一型のベクタ参照)。
R7RSはバイトベクタを定義しています。Gaucheではそれは単に
gauche.uvector
モジュールのu8vector
です
(R7RSモジュールは別名を定義しています。R7RS基本ライブラリ参照。)
より多くのベクタに対する操作がR7RSベクタで提供されています。
[R7RS base]
objがベクタなら#t
を、そうでなければ#f
を返します。
[R7RS base] 長さkのベクタを作成して返します。 省略可能な引数fillが与えられていれば、ベクタの各要素はその値で 初期化されます。そうでなければベクタの各要素の値は不定です。
[R7RS base] 要素がobj …であるようなベクタを作成して返します。
長さlenのベクタを作成し、0
以上len未満のiについて
i番目の要素を(proc i)
の値で初期化します。
(vector-tabulate 5 (^x (* x x))) ⇒ #(0 1 4 9 16)
[R7RS base] ベクタvectorの長さを返します。
gauche.collection
モジュールをロードしていれば、
メソッドsize-of
も同じ目的で使えます。
[R7RS+] ベクタvectorのk番目の要素を返します。
vector-ref
はkが負の値であったりベクタの長さより
大きかったりした場合はエラーを通知します。但し、省略可能な引数fallback
が与えられている場合はその値が返されます。これはGaucheの拡張です。
gauche.sequence
モジュールをロードしていれば、
メソッドref
も同じ目的で使えます。
[R7RS base] ベクタvectorのk番目の要素をobjに変更します。 kが負数であったりベクタの長さより大きい場合はエラーとなります。
gauche.sequence
モジュールをロードしていれば、
メソッドref
のsetterメソッドも使えます。
[R7RS+] ベクタをリストに変換したり、その逆を行う手続きです。
省略可能な引数startとendを与えることにより、
値を取り出す範囲を制限することができます。
(R7RSのlist->vector
はstartとend引数を規定していません。)
(vector->list '#(1 2 3 4 5)) ⇒ (1 2 3 4 5) (list->vector '(1 2 3 4 5)) ⇒ #(1 2 3 4 5) (vector->list '#(1 2 3 4 5) 2 4) ⇒ (3 4) (list->vector (circular-list 'a 'b 'c) 1 6) ⇒ #(b c a b c)
gauche.collection
モジュールをロードしていれば、
(coerce-to <list> vector)
と
(coerce-to <vector> list)
も同じ目的で使えます。
[R7RS vector]
省略可能引数が無い場合、
(list->vector (reverse list))
と同じ結果を返しますが、
中間リストを作りません。省略可能引数startおよびendが
与えられた場合は、それはlistの範囲を指定します。
(reverse-list->vector '(a b c d e f g) 1 5) ⇒ #(e d c b)
[R7RS base]
文字のベクタを文字列に変換したり、その逆を行う手続きです。
vector->string
に、文字以外の要素を含むベクタを渡した場合はエラーになります。
省略可能な引数startとendを与えることにより、 値を取り出す範囲を制限することができます。
(vector->string '#(#\a #\b #\c #\d #\e)) ⇒ "abcde" (string->vector "abcde") ⇒ #(#\a #\b #\c #\d #\e) (vector->string '#(#\a #\b #\c #\d #\e) 2 4) ⇒ ("cd")
gauche.collection
モジュールをロードしていれば、
(coerce-to <string> vector)
と
(coerce-to <vector> string)
も同じ目的で使えます。
[R7RS base] ベクタvectorの全ての要素をfillに変更します。
省略可能な引数startとendが与えられた場合、 start番目の要素からend-1番目の要素までのみに fillを格納します。startとendの既定値は それぞれ0とvectorの大きさです。
[R7RS base] ベクタvectorをコピーします。引数startとendを与えることで コピーされる範囲を制限することができます。 startとendで指定される範囲が元のvectorの範囲を越えた 場合は、その部分がfillで埋められます。
(vector-copy '#(1 2 3 4 5)) ⇒ #(1 2 3 4 5) (vector-copy '#(1 2 3 4 5) 2 4) ⇒ #(3 4) (vector-copy '#(1 2 3 4 5) 3 7 #f) ⇒ #(4 5 #f #f)
[R7RS base] ベクタsourceの内容をベクタtargetのインデックスtstart以降に コピーします。targetは変更可能でなければなりません。 省略可能なsstartとsend引数はコピー元ベクタの範囲を限定します。
(rlet1 v (vector 'a 'b 'c 'd 'e) (vector-copy! v 2 '#(1 2))) ⇒ #(a b 1 2 e) (rlet1 v (vector 'a 'b 'c 'd 'e) (vector-copy! v 2 '#(1 2 3 4) 1 3)) ⇒ #(a b 2 3 e)
コピーされるデータが、コピー先の領域(tstartから末尾まで)より 大きい場合はエラーが報告されます。
targetとsourceに同じベクタを渡しても構いません。 コピー元とコピー先の領域に重なりがある場合でもこの手続きは使えます。
[R7RS base] ベクタvecを順に継ぎ足した内容を持つベクタを新たに作成して返します。
(vector-append '#(1 2 3) '#(a b)) ⇒ #(1 2 3 a b) (vector-append) ⇒ #()
[R7RS base] ベクタvec1 vec2 …の各i番目の要素にprocを 適用したものをi番目の要素とする新たなベクタを作って返します。 結果のベクタの長さは、引数のベクタのうち最も短いものと同じになります。
(vector-map + '#(1 2 3) '#(4 5 6 7)) ⇒ #(5 7 9)
procが呼ばれる順番は定義されておらず、将来のバージョンで変わるかもしれないので、 procでは順序に影響されるような副作用を起こしてはいけません。
註: gauche.collection
をuseして
(map-to <vector> proc vec1 vec2 …)
としても同じ機能は得られます。
vector-map
と似ていますが、procの第1引数に
現在のインデックスが渡されます。
(vector-map-with-index list '#(a b c d e) '#(A B C)) ⇒ #((0 a A) (1 b B) (2 c C))
これがSRFI-43でvector-map
と呼ばれている手続きです。
ベクタライブラリ(旧式)参照。
註: gauche.collection
をuseして
(map-to-with-index <vector> proc vec1 vec2 …)
としても同じ機能は得られます。
[R7RS vector] 各インデックスiについて、ベクタvec1 vec2 …の i番目の要素を引数としてprocを呼び出した結果、vec1の i番目の要素にセットします。ベクタの長さが異なる場合は最も短いベクタ の範囲が計算されます。
(rlet1 v (vector 1 2 3) (vector-map! ($ + 1 $) v)) ⇒ #(2 3 4) (rlet1 v (vector 1 2 3 4) (vector-map! + v '#(10 20))) ⇒ #(11 22 3 4)
vector-map!
と似ていますが、procの第1引数に
現在のインデックスが渡されます。SRFI-43でvector-map!
と定義されているものと同じ動作です (ベクタライブラリ(旧式)参照)。
(rlet1 v (vector 'a 'b 'c) (vector-map-with-index! list v)) ⇒ #((0 a) (1 b) (2 c))
[R7RS base] 0から渡されたベクタのうち一番短いものの最大のインデックスまでのiについて、 vec1 vec2 …のそれぞれi番目の要素を引数に procを呼び出します。
(vector-for-each print '#(a b c))
⇒ prints a
, b
and c
.
vector-for-each
と似ていますが、procの第1引数に
現在のインデックスが渡されます。
この手続きはSRFI-43のvector-for-each
と等価です。
ベクタライブラリ(旧式)参照。
ユニフォームベクタ、あるいは同質な数値ベクタは、
要素として特定の数値型のみを格納する特別なベクタです。
もともとsrfi-4として導入され、srfi-160で改訂されたのち、
R7RS largeの一部となりました(scheme.vector.@
モジュール)。
@
の部分は実際には要素の型を示す以下のタグのいずれかです。
u8
8ビット符号無し整数 - 0から255までの正確な整数。
s8
8ビット符号つき整数 - -128から127までの正確な整数。
u16
16ビット符号無し整数 - 0から65535までの正確な整数。
s16
16ビット符号つき整数 - -32768から32767までの正確な整数。
u32
32ビット符号無し整数 - 0から 2^32 - 1 までの正確な整数。
s32
32ビット符号つき整数 - -(2^31) から 2^31 - 1 までの正確な整数。
u64
64ビット符号無し整数 - 0から 2^64 - 1 までの正確な整数。
s64
64ビット符号つき整数 - -(2^63) から 2^63 - 1 までの正確な整数。
f16
16ビット浮動小数点数(仮数部10ビット、指数部5ビット)で表される不正確な実数
f32
IEEE単精度浮動小数点数で表される不正確な実数
f64
IEEE倍精度浮動小数点数で表される不正確な実数
c32
2つの16ビット浮動小数点数で表される不正確な複素数
c64
2つのIEEE単精度浮動小数点数で表される不正確な複素数
c128
2つのIEEE倍精度浮動小数点数で表される不正確な複素数
通常のベクタではなくユニフォームベクタを使うことにより得られる利点がいくつかあります。 まず、ユニフォームベクタは通常のベクタよりもコンパクトです。 いくつかのオペレーション(特に、Gaucheの拡張仕様であるベクタ上の数値演算)では、 型検査と型変換を個々の要素に対して行わなくても良いため、 極めて効率の良い演算が可能です。さらに、 数値の配列を扱う外部のライブラリとのインタフェースが容易です。 例えば、GaucheのOpenGLバインディングではユニフォームベクタを多用しています。
Gaucheは組み込みではごく基本的な手続きしか提供しませんが、
gauche.uvector
モジュールやscheme.vector.@
モジュール
(R7RSでは(scheme vector @)
ライブラリ)では包括的な操作を提供しています。
ユニフォームベクタライブラリおよびR7RSユニフォームベクタ参照。
ユニフォームベクタクラスのベースクラスです。<sequence>
を継承します
(シーケンスフレームワーク参照)。
{gauche.uvector}
@vectorのクラス。@
の部分はuvectorタグ
(u8
、s8
、…) です。
<uvector>
を継承します。
sequenceプロトコル(シーケンスフレームワーク参照)を実装しているので、
数値の並びをcoerce-to
を使ってuvectorに変換することができます。
ただし各要素はuvectorの要素として有効な範囲の値でなればなりません。
(use gauche.sequence) (coerce-to <u8vector> '(1 2 3)) ⇒ #u8(1 2 3)
#u8(n …)
#s8(n …)
#u16(n …)
#s16(n …)
#u32(n …)
#s32(n …)
#u64(n …)
#s64(n …)
#f16(n …)
#f32(n …)
#f64(n …)
#c32(n …)
#c64(n …)
#c128(n …)
リテラルの単一型のベクタを記述します。
(註: R7RSのバイトベクタはu8vectorと同じで、#u8(…)
で表記できます。)
#s8(3 -2 4) #u32(4154 88357 2 323) #f32(3.14 0.554525 -3.342)
[R7RS vector.@] 長さlenの@vectorを作成して返します。各要素はfillで 初期化されます。正確な整数のベクタに対しては、fillは正確な整数でなければならず、 また有効な範囲内の値でなければなりません。 fillが省略された場合、各要素の初期値は不定です。
(make-u8vector 4 0) ⇒ #u8(0 0 0 0)
objがユニフォームベクタのいずれかなら#t
を、
そうでなければ#f
を返します。
特定の型のuvectorを検査する述語については後で説明します。
uvectoruvの長さ(要素数)を返します。 uvがuvectorでなければエラーを投げます。
特定の型のuvectorの長さを取る手続きは、scheme.vector.@
および
gauche.uvector
にあります (ユニフォームベクタライブラリ参照)。
uvectorの内容がバイナリデータとして占有する大きさを知りたければ、
gauche.uvector
のuvector-size
が使えます。
汎用的なuvectorのアクセサです。uvector uvのk番目の 要素を返します。kが範囲外の場合、fallbackが与えられていればそれが 返され、そうでなければエラーが投げられます。
この手続きは様々な種類のユニフォームベクタに対して動作するような一般的なコードを
書く際にとても便利ですが、それぞれの種類のユニフォームベクタ専用の
アクセサに比べると遅いです。Gaucheのコンパイラは@vector-ref
の
呼び出しを認識して非常に効率の良いコードを出すのに対し、
この手続きは通常の手続き呼び出しになるからです。内部のループ内で呼び出す場合、
これは大きな差になるかもしれません。
型ごと専用のアクセサは下で説明します。
なお、(setter uvector-ref)
はuvector-set!
です。
汎用的なuvectorのセッターです。uvector uvのk番目の要素を valで置き換えます。 kが範囲外であったり、 uvが変更不可である場合はエラーが投げられます。
省略可能な引数clampが、valが正しい範囲外の数であった場合の動作を指定します。
この引数は#f
か、
シンボルlow
、high
、both
のいずれかでなければなりません。
この意味についてはユニフォームベクタライブラリを参照してください。
デフォルトは#f
で、範囲外の値についてはエラーを投げます。
型ごとの述語、アクセサ、セッタはここで提供されます。
他の手続きについてはscheme.vector.@
やgauche.uvector
を
利用してください (ユニフォームベクタライブラリ参照)。
[R7RS vector.@]
objが@vectorなら#t
を、そうでなければ#f
を返します。
@
の部分はuvectorタグ(u8
等)です。
[R7RS vector.@]
@vector vecのk番目の要素を返します。
@
の部分はuvectorタグ(u8
等)です。
kが有効な範囲外であった場合、通常はエラーが通知されますが、 省略可能な引数fallbackが与えられている場合はそれが返されます。
モジュールgauche.collection
をインポートしていれば、
総称関数ref
を使うこともできます。
(u16vector-ref '#u16(111 222 333) 1) ⇒ 222 (use gauche.collection) (ref '#u16(111 222 333) 1) ⇒ 222
@vector-ref
のsetterは@vector-set!
です。
(use gauche.uvector) (define v (u8vector 1 2 3)) (set! (u8vector-ref v 1) 99) v ⇒ #u8(1 99 3)
[R7RS vector.@]
@vector vecのk番目の要素に数値nをセットします。
@
の部分はuvectorタグ(u8
等)です。
省略可能な引数clampが、nが正しい範囲外の数であった場合の動作を指定します。
この引数は#f
か、
シンボルlow
、high
、both
のいずれかでなければなりません。
この意味についてはユニフォームベクタライブラリを参照してください。
デフォルトは#f
で、範囲外の値についてはエラーを投げます。
モジュールgauche.collection
をインポートしていれば、
総称関数ref
のsetter手続きを使うこともできます。
(let ((v (s32vector -439 852 8933))) (s32vector-set! v 1 4) v) ⇒ #s32vector(-439 4 8933) (use gauche.collection) (let ((v (s32vector -439 852 8933))) (set! (ref v 1) 4) v) ⇒ #s32vector(-439 4 8933)
ビットベクタはビットの並びです。各「ビット」は、0/1の数値としても、
#f
/#t
の論理値としても解釈可能です。
最初の見方では、ビットベクタをユニフォームベクタの一種と考えることもできますが、
インタフェースがそこそこ違っているので、別の型としました。
Gaucheはコアでごく基本的な手続きを提供します。 SRFI-178に包括的なビットベクタライブラリがあります。 ビットベクタライブラリを参照してください。
ビットベクタクラス。<sequence>
を継承し、ジェネリックなシーケンス操作も使えます。
(ジェネリックなref
については、
外部表現との親和性からbitvector-ref/int
が使われます)。
#*b…
[SRFI-178]
ビットベクタリテラルは、#*
のあとに0
や1
が0個以上続いたものです。
#*10010010 ; bitvector of length 8 #* ; bitvector of length 0
ビットベクタリテラルはデリミタ文字かEOFで区切られます。
#*10010abc ; error #*10001(a b c) ; a bitvector, followed by a list
註: このルールでは、#*"..."
は、
長さゼロのビットベクタと文字列、と解釈されるべきです。"
は区切り文字ですから。
しかし、Gaucheでは長らくこの構文を不完全文字列に使っていました。
(長さゼロのビットベクタがあることを見落としてました!)
不完全文字列の外部表記が必要になることは滅多にないので
(不完全文字列は現実のデータを扱う際にどうしても「生じてしまう」もので、
積極的に使うべきではありません)、
その表記は0.9.10から#**"..."
に変更されました (不完全文字列)。
後方互換性のため、現在のバージョンでは#*"..."
は不完全文字列として読まれます。
リーダー字句モードがwarn-legacy
であれば、この形のリテラルに対して警告が出されます
(リーダー字句モード)。
将来的には#*"..."
はビットベクタと文字列として読まれるように徐々に以降する予定です。
[SRFI-178]
ビットベクタAPIでビットが必要なところには、論理値(#f
/#t
)あるいは
正確な整数 (0/1)を渡すことができます。これらの手続きは有効なビット値をそれぞれ0/1もしくは
#f
/#t
に揃えます。bitが有効なビット値でなければエラーが投げられます。
[SRFI-178] 要素がb …であるビットベクタを作って返します。 各引数はビット値でなければなりません (論理値か0か1)。
(bitvector 0 1 0 0 1 0 0 0 1) ⇒ #*010010001 (bitvector) ⇒ #*
[SRFI-178] 長さlenのビットベクタを作って返します。各要素はinitで初期化されます。 initはビット値(論理値か0か1)でなければなりません。
initが省略された場合、ビットベクタの内容は未定義です。 (今のところ0で初期化されますが、それをあてにしてはいけません)。
(make-bitvector 5 #f) ⇒ #*00000 (make-bitvector 7 1) ⇒ #*1111111
[SRFI-178] lisはビット値(論理値、0、1)のリストでなければなりません。 それらの値を要素とするビットベクタを作って返します。
(list->bitvector '(#t #f #t #t #f)) ⇒ #*10110 (list->bitvector '(0 1 1 1 0 1 0 1)) ⇒ #*01110101
[SRFI-178]
s
がビットベクタリテラルとして有効な文字列
(#*b...
でbが0
か1
)
であれば、それで表現されるビットベクタを返します。そうでなければ#f
が返されます。
(string->bitvector "#*1010001") ⇒ #*1010001 (string->bitvector "#*1001020") ⇒ #f
これはシーケンスとしての変換ではなく、外部表現からの変換であることに注意してください。
[SRFI-178]
ビットベクタbvの外部表現#*b...
を文字列として返します。
(bitvector->string #*1001010) ⇒ "#*1001010"
これはシーケンスとしての変換ではなく、外部表現への変換であることに注意してください。
[SRFI-178+] ビットベクタbvのk番目の要素を、それぞれ整数0/1か論理値として返します。 kが範囲外だった場合、fallbackが与えられていればそれが返され、 与えられていなければエラーが投げられます。 fallback引数はGaucheの拡張です。
(bitvector-ref/int #*1010001 0) ⇒ 1 (bitvector-ref/bool #*1010001 0) ⇒ #t
万能アクセサref
/~
をビットベクタに使った場合は、
整数値が返されます (万能アクセサ)。
(~ #*11001001 1) ⇒ 1
[SRFI-178]
ビットベクタbvのk番目の要素にビット値bitをセットします。
bitは0、1、#f
、#t
のいずれかでなければなりません。
kが範囲外ならエラーが投げられます。
この手続きはbitvector-ref/int
とbitvector-ref/bool
のsetterとして
設定されています。また、ビットベクタはシーケンスなので、
(setter ref)
/(setter ~)
も使えます。
(rlet1 z (make-bitvector 5 0) (set! (~ z 2) #t)) ⇒ #00100
[SRFI-178] ビットベクタbvのコピーを作って返します。 省略可能引数start、endでインデックスが与えられた場合は、 その範囲内がコピーされます。startは含まれ、endは含まれません。
(bitvector-copy #*101001000 3) ⇒ #*001000 (bitvector-copy #*100101000 2 7) ⇒ #*01010
[SRFI-178] ビットベクタsrcの内容を、 変更可能なビットベクタtargetのtstartインデックス以降にコピーして targetの内容を書き換えます。省略可能なsstart、sendは srcのコピーされる範囲を限定します。
(rlet1 v (make-bitvector 10 0) (bitvector-copy! v 3 #*101101110 2 6)) ⇒ #*0001101000
Weak ポインタとは、それが参照しているオブジェクトがガベージコレクトされることを
許すようなポインタです。
Gaucheはweak ベクタオブジェクトによってweak ポインタの機能を提供します。
Weak ベクタは通常のベクタに似ていますが、要素のオブジェクトがweak ベクタ以外から
参照されていない場合、オブジェクトはガベージコレクトされ、weak ベクタの該当するエントリは
#f
で置き換えられます。
gosh> (define v (make-weak-vector 1)) v gosh> (weak-vector-ref v 0) #f gosh> (weak-vector-set! v 0 (cons 1 1)) #<undef> gosh> (weak-vector-ref v 0) (1 . 1) gosh> (gc) #<undef> gosh> (gc) #<undef> gosh> (weak-vector-ref v 0) #f
R7RS-largeでのweakポインタについてはR7RS Ephemeronを参照してください。
Weak ベクタのクラスです。<sequence>
と<collection>
を継承しているので、
gauche.collection
(コレクションフレームワーク参照) と
gauche.sequence
(シーケンスフレームワーク参照) も使えます。
(coerce-to <weak-vector> '(1 2 3 4)) ⇒ a weak vector with four elements
大きさsizeのweak ベクタを作成して返します。
weak ベクタ wvecの大きさを返します。
weak ベクタ wvecのk番目の要素を返します。
weak-vector-ref
はkが負の値であったりベクタの長さより
大きかったりした場合はエラーを通知します。但し、省略可能な引数fallback
が与えられている場合はその値が返されます。
該当する要素が既にガベージコレクトされていた場合、fallbackが
与えられていればそれが、そうでなければ#f
が返されます。
gauche.sequence
モジュールをロードしていれば、
メソッドref
も同じ目的で使えます。
weak ベクタ wvecのk番目の要素をobjに変更します。 kが負数であったりベクタの長さより大きい場合はエラーとなります。