Top / Alan言語仕様 / データ型

データ型

Alan でサポートしているデータ型は下記です:
  1. 基本型
    型名 説明
    int 整数型。32bit です。
    str 文字列型
    byte byte型。8bit です。
    bool 論理値型
    rex 正規表現型。
    file ファイル型。
    real 実数型。
    void void型。戻り値のない関数を定義するときに使用。
    substr (v0.09) 部分文字列型
    files (v0.09) files型。 stdins (Perlのダイヤモンド演算子 <>に相当) のために導入。
    type (v0.17) type型。 RTTIへの布石
    err (v0.23) 例外処理で使用する例外コード型。
  2. コンテナ型
    型名 説明
    array[T], array2[T] 配列型。T は任意の型です。array2 は2次元配列用。
    list[T] リスト型。
    map, map[T] (v0.09) map(連想配列)型。

コンストラクタ式 T(...)

(v0.16) 任意の型 T に対してコンストラクタ T: t = (...) が存在する場合、T の一時変数を T(...) として作成することが 可能になりました。C++ からのパクリです。

一時変数の寿命は C++ と同様、部分式でない式までです。

例
  1. # list OS users in this machine
    
    for str:s in file("/etc/passwd") do
       put(s.split(':')(0), "\n")
    end
    
    反復子の一時変数 file("/etc/passwd") の寿命は for文全体です。
  2. # logging, (but inefficient)
    import Time end
    
    file("/tmp/x", file.WRITE).putf("% %\n", now, "Hello, World")
    put("next...\n")
    
    この一時変数 file("/tmp/x") の寿命は一行で終わります。 そのため、(破棄子によって)4行目でファイルは自動的に close され、 5行目の処理(put)に移ります。

以下、型ごとに説明していきます。

int

32bit 符合つき整数です。

リテラル

・・・など。

演算子

比較 ==, <>, <, <=, >, >=
加減 +, -
乗除 *, /, mod
単項マイナス -

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
init (int) # コピーコンストラクタ
全型共通メンバ
int: size # サイズ(byte)

int.init()

説明
初期値が無い場合、0 に初期化されます。
例
int: i      # 0に初期化されます
put(i)

int.init(int)

説明
初期値を指定して変数を生成します。
例
int: i = 123      # 123に初期化されます
put(i)

int: int.size

説明
int型変数の使用サイズ(byte数)を返します。
戻り値
サイズ(byte数)
例

str

リテラル

Double-quote で囲った文字が文字列リテラルです。

円記号(\)(またはバックスラッシュ)によるエスケープとして現在サポート しているのは下記となります:
\n 改行, LF, 0x0a
\r キャリッジリターン, CR, 0x0d
\t タブ, TAB, 0x09

演算子

比較 ==, <>, <, <=, >, >=
加 +

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
init (str) # コピーコンストラクタ
全型共通メンバ
全コンテナ型共通メンバ
int size # 要素数(byte数)を得る
byte operator() (int i) # i番目の要素(文字)へのアクセス
固有メンバ
str: gsub () # 大域文字列置換
int: index (str) # 文字列検索(非正規表現)
str: lower # 小文字に変換
list: split (byte) # 文字列のbyteへの分割
str: upper # 大文字に変換
substr: trim # 前後の空白(改行・タブを含む)を取り除く (v0.10)
固有メンバ(型変換系)
int: hex # (v0.15)16進と見て整数値に変換
int: int # 整数値に変換
int: real # 実数に変換
int: real8 # 倍精度実数に変換

str.init()

説明
変数定義時、空文字列で初期化します。
例
str: s            # 空文字列("")で s を生成
put('(', s, ')')  # () が印字される

str.init(str)

説明
初期値 s で文字列を初期化します。
例
str: s = "Hello"
put(s)

str: str.gsub(str:pattern, str:replace)
str: str.gsub(rex:pattern, str:replace)

説明
(v0.15) 文字列 str 中のパターン ptn を全て replace で置き換える。 str自身は変更ありません。
戻り値
置き換えられた文字列
例
put("Hello  Alan!".gsub("l", "ELL"), "\n")
put("Hello  Alan!".gsub(/ *A/, "a"), "\n")
BUG
Perl の s///ge, Ruby の gsub(//){...} に相当する機能は まだありません。(これが closure だと最近知りました)

int: str.index(str: key)

説明
文字列 str をキーワード key で検索する。
戻り値
>=0 マッチする部分文字列のオフセット値
-1 見つからなかった場合
例
TBD

str: str.lower

説明
全て小文字に変換します。元の文字列には影響しません。
戻り値
全て小文字に変換された文字列。
例
TBD
SEE ALSO
upper 大文字に変換

int: str.size

説明
要素( = byte)の数を返します。

※ メンバ size はコンテナ型(*)に共通で、要素数を返します。 str の場合、byte 数、となります。

(*) 要素型を複数「格納する」(コンテナ)する型。 配列型、リスト型、マップ型がこれに相当します。文字列は byte の列 なので、コンテナ型の1種と見ることができます。

戻り値
要素( = byte)の数
例
str: s = "Hello, World!"
put(s.size);    # 要素数(=byte数) 13 が印字される。
SEE ALSO

byte: str.operator()(int i)

説明
i 番目の要素(=文字) を返します。
ここで i は 0 <= i < size の間の値です。
戻り値
i番目の文字
例
str: s = "Hello,World";
put(s(1), "\n");    # 'e' が印字
SEE ALSO
BUG
i が範囲以外の値の場合、例外を発生させるべきですが、 今は不定値を返します。

list: str.split(byte: ch)

説明
byte文字 ch を区切子(separator)として文字列 str を分割し、 文字列リストを返す。
戻り値
分割された文字列のリスト
例
# /etc/passwd からユーザ名とホームディレクトリを印字

file: f = "/etc/passwd"
for str: s in f do
   list[str]: l = s.split(':')
   put(l(0), "\t", l(5), "\n")
end
SEE ALSO
BUG
Perl/Ruby に習い、ch のところは本来正規表現とすべきところです。 が、今のところ list の実装の テストを目的として作成したに過ぎないので、簡単のために 文字型 ch をセパレータとしています。

str: str.upper

説明
全て大文字に変換します。元の文字列には影響しません。
戻り値
全て大文字に変換された文字列。
例
TBD
SEE ALSO
lower 小文字に変換

substr: str.trim

説明
(v0.10) 前後の空白(改行・タブを含む)を取り除いた 部分文字列を返します。元の文字列には影響しません。

Perl の chop 的な用途としてでっち上げました。

戻り値
前後の空白(改行・タブを含む)を取り除いた部分文字列
例
# /etc/passwd にセットされている login シェルをリスト。
#
# login シェルは一番最後のカラムなので、そのまま split(':') すると
# 改行が含まれます。
# Perl ではここで chop しますが、これを trim でやってみます:

file: f = "/etc/passwd"
for str: s in f do
    put(s.trim.split(':')(6), "\n");
end
SEE ALSO

int: str.int
int: str.hex

説明
文字列を数値と見て整数型に変換します。 int は10進と見て整数値に変換します。

hex は16進と見て整数値に変換します。頭に 0x がある場合は スキップしてその次から見ていきます。

例外
変換できない文字列が含まれている場合、例外 VE_STR_CONV_INT が発生します。
戻り値
変換された文字列
例
put("10".int + 3, "\n")
put("10".hex + 3, "\n")
put("0x10".hex + 3, "\n")
SEE ALSO

real: str.real
real8: str.real8

説明
文字列を実数値と見て、実数値に変換します。
戻り値
変換された実数値
例外
変換できない文字列が含まれている場合、例外 VE_STR_CONV_REAL, VE_STR_CONV_REAL8 が発生します。
例
put("3.14".real  / 2.0, "\n")
put("3.14".real8 / 2.0, "\n")
SEE ALSO

byte

byte型 = 8bit 符合無し整数です。

リテラル

シングル・クォート(')で囲った文字を定数として使用できます。

円記号(\)(またはバックスラッシュ)によるエスケープは 文字列のそれと同じです。

例
byte: ch = 'a'
put(ch)

演算子

比較 ==, <>, <, <=, >, >=
加減 +, -
乗除 *, /, mod

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
init (byte) # コピーコンストラクタ
全型共通メンバ
int: size () # サイズ(byte数)

byte.init

説明
初期値が明示されてない場合、ヌル文字 '\0' で初期化されます。
例
byte: c
put(c, "!\n")

byte.init(byte)

説明
文字型を初期値として文字型変数を生成します。
例
byte: c = 'X'
put(c, "\n")

int: byte.size

説明
文字変数で使用するサイズ(byte数)を返します。
戻り値
サイズ(byte数)
例

bool

リテラル

演算子

論理和 or
論理積 and
論理否定 not
比較 ==, <>
BUG
A or B の場合、A が真なら B は評価しない、というのが C/C++ 系の論理演算で、Alan でもそう実装する予定ですが まだ実現していません。 A and B も同様です。

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
init (bool) # コピーコンストラクタ
全型共通メンバ
int: size () # サイズ(byte数)

bool.init

説明
初期値が明示されてない場合、false で初期化されます。
例
bool: b
put(b)

bool.init(bool)

説明
bool型の初期値でbool型変数を生成します。
例
bool: b = true
put(b)

int: bool.size

説明
bool変数で使用するサイズ(byte数)を返します。
戻り値
サイズ(byte数)
例

rex

正規表現の型名は rex としました。 "regular expression" の略です。

(v0.09) マッチした部分文字列が取り出せるようになりました。

リテラル

awk, perl, ruby 達と同様、2つのスラッシュで挟んだ文字列 /.../ は、 そのまま正規表現によるパターンマッチに使えます:
/[Hh]ello/ # 大文字 H か小文字 h で始まる hello にマッチするか
例
for str: s in stdin do
   if s in /[Hh]ello/ then
      put(s)
   end
end
ただし、マッチした文字列を取り出す場合、awk や Perl のように $i を使うようには出来ていません。この場合、 matched メンバへのアクセスによって行うようにしていますので、 リテラルではなく rex 型変数を使って下さい。 (v0.15 直しました -> matched())
BUG
rex r; put(r); が SEGV core-dump するバグを今更ながら発見しました。 v0.10 で直します。 (v0.12 fixed)

演算子

パターンマッチ in (但し、str in rex という組合わせのみ)

メンバ

コンストラクタ
init (str) # コンストラクタ
全型共通メンバ
int: size () # サイズ(byte数)
固有メンバ
int: matched_size # マッチした部分文字列の個数
substr: matched (int i) # i番目のマッチした部分文字列

rex.init(str)

説明
文字列 s で表現された正規表現で持って rex型変数を 初期化します。
例
# str in /[Hh]ello/ を rex 変数で行う例:

rex: r = "[Hh]ello"
for str: s in stdin do
   if s in r then
      put(s)
   end
end

int: rex.size

説明
rex変数のサイズ(byte数)を返します。 あくまで初期のサイズであり、正規表現を コンパイルする際に動的に生成される内部的なデータ構造 は含まれていません。
戻り値
サイズ(byte数)
例

int: rex.matched_size

説明
パターンマッチ後、正規表現中 (...)で囲った部分とマッチした 部分文字列の個数を返します。

注: Alan では size には要素の数という意味を持たせています。 matched_size も、マッチした部分文字列リスト中の要素の数 を表しています。また、マッチした部分文字列とは、(...)で囲った部分 の他に、正規表現全体にマッチした部分文字列も含めています。 従って、C の API regcomp() の返す regex_t 型が保持する個数 re_nsub とは同じではなく、それに +1 した数となっています。 例も参照下さい。

戻り値
マッチした部分文字列の個数
例

substr: rex.matched(int: i)

説明
マッチした部分文字列のうち、i番目のものを返します。
i = 0 は、マッチした部分全体の文字列を返します。
i = 1 は、1番目の正規表現中のカッコ(...)で囲った部分文字列を返します。
以下同様で、i = matched_size - 1 までが部分文字列の添字となります。 i がそれ以外の場合、VE_REX_EXCEED_MATCHED_NUM 例外が発生します。
戻り値
部分文字列
例外
VE_REX_EXCEED_MATCH_NUM マッチ部分文字列の数がバッファを超えました。 src/type/rex.h の V_REX_MATCH_NUM を増やして再コンパイル して下さい。
VE_REX_EXCEED_MATCHED_NUM rex.matched(int i) メンバ呼出し時に、添字 i が範囲を超えました。
例
matched_size の例 を参照下さい。

file

ファイル(のイタレータ)です。

今のところ、read-open のみのサポートです。 (v0.09) 書き込みオープン出来るようになりました。

演算子

なし。Iterator での指定のみ

メンバ

コンストラクタ
init (str) # コンストラクタ
init (str, int) # コンストラクタ
全型共通メンバ
int: size () # サイズ(byte数)
固有メンバ
int: READ # read open モード
int: WRITE # write open モード
void: put (...) # 印字
void: putf (str:fmt, ...) # 書式付き印字
void: putf (Fmt:fmt, ...) # 書式付き印字 (書式をコンパイル済)

以下、詳しく説明します。

file.init(str)

説明
文字列で指定されたファイルを read オープンします。

スコープを抜けた時点で自動的に close します。

例外
VE_FILE_OPEN_FAIL --オープンに失敗しました。
例
for str: s in file("/etc/passwd") do
  put(s)
end
例の解説: file("ファイル名") とは、型(初期値) という 文法で一時変数を作成する Alan の記法です(C++からの借用)。 裏では file型変数が file.init("ファイル名") という初期化メンバ関数で 初期化され、for文の間有効となり、"s in file(..." の個所で ファイルが一行ずつ取得され、put(s) で印字される、という例です。

for文のスコープを抜けた時点で自動的に破棄子が呼ばれ ファイルは close されます。

file.init(str: name, int: mode)

説明
文字列 name で指定されたファイルをオープンします。 オープンモード mode として以下が指定可能です:
int file.READ 読み込みモードでオープンします。
int file.WRITE 書き込みモードでオープンします。

スコープを抜けた時点で自動的に close します。

例外
VE_FILE_OPEN_FAIL --オープンに失敗しました。
例
file: f = ("/tmp/x", file.WRITE)
f.put("Hello, World!\n")
スコープを抜けた時点で自動的に close するので、 確かに /tmp/x に Hello, World が保存されていることを 確認してみてください。

int: file.size

説明
file型変数のサイズ(byte数)を返します。
戻り値
サイズ(byte数)
例

int: file.READ

説明
READ モードで file をオープンするための名前つき定数です。 変数初期化時に mode を省略すると自動的に READ モードで open されるので、通常使うことはありません。
例
file: f = ("/etc/passwd", file.READ)

int: file.WRITE

説明
WRITE モードで file をオープンするための名前つき定数です。
例
init()の例を 参照下さい。

void: file.put(...)

説明
ファイルに対して印字します。
例
file: f = ("/tmp/x", file.WRITE)
f.put("Hello, World!\n")
SEE ALSO

put() -- stdout への印字
file.putf() -- 書式付き印字

void: file.putf(str:fmt, ...)
void: file.putf(Fmt:fmt, ...)

説明
書式付き印字をファイルに対して行います。
書式については putf() を参照下さい。
第一引数の Fmt は、文字列による書式をコンパイルしたものです。 なので、複数回使用する場合に効率的です。
例
file: f = ("/tmp/x", file.WRITE)
f.putf("%<<<<<<< %>>>>>.>>\n", "Hello", real.PI)

# 同じことを1行で行えます(が、何回も putf() する場合は上のようにしましょう)
file("/tmp/x2", file.WRITE).putf("%<<<<<<< %>>>>>.>>\n", "Kuma", real.PI)

# stderr への書式付きロギングの例です:
import
   Time
end
stderr.putf("% %\n", now, "syntax error!")

real, real8

実数(浮動小数点数)型として、32bit 実数である real 型と、64bit実数 real8 型を サポートしています。

以下、real型のみ説明していますが、特に断らない限り real8 にも同様に適用できます。

演算子

比較 ==, <>, <, <=, >, >=
加減 +, -
乗除 *, /, mod
単項マイナス -

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
init (real) # コンストラクタ
init (int) # コンストラクタ
全型共通メンバ
int: size # サイズ(byte数)
固有メンバ
# 三角関数系
real: sin
real: cos
real: tan
real: asin
real: acos
real: atan
# 指数系
real: exp # ex
real: log
real: log10
# 平方根
real: sqrt # √x
# 誤差系
real: ceil # 切り上げ
real: floor # 切り捨て
real: round # 四捨五入(未実装。round(3)が見つからない。なぜ?)
# 明示的型変換
real: int # real -> int
# その他
real: abs # 絶対値
# 定数
real: E # 自然底数 e
real: PI # 円周率π

以下、詳細です。

NOTE: 数学でよく使う関数(sin,cos, ...)を real型 & real8型の メンバ関数 として定義しています。 通常、C言語などではこれら数学関数は フリー関数 として定義しています。 つまり、

real: sin(real: x); と
real: real.sin;
の両方を提供する予定ということです。 全てをメンバ関数で統一する、という考え方もあるかもしれません。 Eiffel や Smalltalk がそのアプローチを採っているようです。 他方、Alan では、特に混乱がない限りは伝統的表現(フリー関数) も取り入れたいと考えています。

メンバ関数としている理由は、単に「フリー関数の実装の前に名前空間 の問題を解決しておく必要があるがまだそれが出来ていないから」、 と言うものです。 名前空間が実装でき次第、フリー関数も提供する予定です。 (v0.09 対応しました)。

real.init()

説明
初期値がない場合、0.0 で初期化します。
例
real: r
put(r)

real.init(real)

説明
real値によって real型変数を初期化します
例
real: r = real.PI
put(r)

real.init(int)

説明
整数値で real型を初期化します。
例
real: r = 3
put(r)

int: real.size

説明
real型のサイズ(byte数)を返します。
戻り値
サイズ(byte数)
例

real: real.sin

説明
sin 関数を適用します。
戻り値
sin 値
例
real: x = 0.0
put(x.sin, "\n")              # sin(0)
put(real.PI.sin, "\n")        # sin(π); real.PI = π です(後述)
put((real.PI/2.0).sin, "\n")  # sin(π/2); 式にメンバ関数を使う例
SEE ALSO
BUG

real: real.cos

説明
cos 関数を適用します。
戻り値
cos 値
例
real: x = 0.0
put(x.cos, "\n")              # cos(0)
put(real.PI.cos, "\n")        # cos(π);
put((real.PI/2.0).cos, "\n")  # cos(π/2);
SEE ALSO
BUG

real: real.tan

説明
tan 関数を適用します。
戻り値
tan 値
例
real: x = 0.0
put(x.tan, "\n")              # tan(0)
put(real.PI.tan, "\n")        # tan(π); real.PI = π です(後述)
put((real.PI/2.0).tan, "\n")  # tan(π/2); 式にメンバ関数を使う例
SEE ALSO
BUG

real: real.asin

説明
asin 関数を適用します。
戻り値
asin 値
例
real: x = 0.0
put(x.asin)
SEE ALSO
BUG

real: real.acos

説明
acos 関数を適用します。
戻り値
acos 値
例
real: x = 0.0
put(x.acos)
SEE ALSO
BUG

real: real.atan

説明
atan 関数を適用します。
戻り値
atan 値
例
real: x = 0.0
put(x.atan)
SEE ALSO
BUG

real: real.exp

説明
自然底数 e を底とする指数関数 ex を適用します。
戻り値
exp 値
例
real: x = 1.0
put(x.exp)
SEE ALSO
real.log exp の逆関数; eのべき乗根
real.E 自然底数 e の値
BUG

real: real.log

説明
自然底数のべき乗根(loge(x) )を適用します。
戻り値
log 値
例
real: x = 1.0
put(x.log)
SEE ALSO
real.exp log の逆関数; eのべき乗
real.E 自然底数 e の値
BUG

real: real.log10

説明
10を底とするべき乗根(log10(x) )を適用します。
戻り値
log10 値
例
real: x = 10.0
put(x.log10)
SEE ALSO
BUG

real: real.sqrt

説明
平方根 ( √x, sqrt(x) )を適用します。
戻り値
sqrt 値
例
put(2.0.sqrt)     # sqrt(2.0)
SEE ALSO
BUG

real: real.ceil

説明
切り上げます。ceil = 天井です。対する切り下げは floor(床)。 英語の意味を知っていると覚えやすいです。
戻り値
切り上げた値
例
put(real.PI.ceil)     # ceil(π) = 4.0
SEE ALSO
real.floor 切り捨て
real.round 四捨五入(TBD)
BUG

real: real.floor

説明
切り捨てます。
戻り値
floor 値
例
put(real.PI.floor)     # floor(π) = 3.0
SEE ALSO
real.ceil 切り上げ
real.round 四捨五入(TBD)
BUG

int: real.int

説明
整数値に変換します。

型 T における U 型への変換メソッド(メンバ関数)は T.U です。 分かりやすいでしょ?

戻り値
整数値
例
put(real.PI.int, "\n")
put((-real.PI).int, "\n")

real: real.abs

説明
絶対値を返します。
戻り値
絶対値
例
put((-1.0).abs)
SEE ALSO
BUG

real: real.E

説明
自然底数 e (の定数)です。
戻り値
2.71828...
例
put(real.E)
SEE ALSO
real.exp log の逆関数; eのべき乗
real.log exp の逆関数; eのべき乗根
BUG

real: real.PI

説明
円周率 π (3.14...) (の定数)です。
戻り値
3.1415...
例
put(real.PI)
SEE ALSO
BUG

void

void型は、「型ではない」ことを表す型です。 やや自己矛盾しているような表現ですが、実際のところは C と同様、関数の戻り値がない場合(=手続き)を表現するものです。

部分文字列型

v0.09 で導入されました。

正規表現でマッチした部分文字列を取り出す際に使用されます。 通常使用するぶんには、普通の文字列と同様なものと考えてかまいません。

演算子・メンバは文字列型を参照下さい。
substr型が発生する部分は正規表現型 の matched() メンバ関数を参照下さい。

BUG
substr -> str の暗黙の型変換は必要なのですが、 まだ実現できていません。従って、下記はまだ動作しません:
# マッチした部分文字列を関数 f() に渡そうとする -> 動かない
void: f(str: s) begin 
    put(s, "\n")
end

rex: r = "(Hello)"
"abcdef" in r
f(r.matched(1))
しかも、そのエラーメッセージが
(stdin):error: undefined ID(f)
0006 f(r.matched(1));
     ^
と、一見意味不明。これでは何のことか分からないですよね。 原因は、
  1. substr -> str に暗黙に型変換できない。
  2. 関数の引数の型整合性に引っ掛かった場合のエラーメッセージが "undefined ID" と不適切。
・・・から来ています。ver0.10 で直します。
(v0.12 fixed)

files型

Perl のダイヤモンド演算子 <> に相当する、Alan の組込みのグローバル変数 stdins を表す型です。

詳細は stdins で説明します。

type型

型も引数に渡したり比較したり put() で印字できます。

演算子

比較 ==, <>

例

void: f(type: t)
   if t == int then
      put(t, " is int\n")
   else
      put(t, " is not int\n")
   end
end

   f(int)
   f(real)
   f(rex)
   f(array[int])

err

raise()時、rescue時に指定するエラーコード値を表す型です。 意味的には 同じv0.23 で導入された enum 型の1つで、 enum err NO_ERR, RUNTIME, ... end と定義されます。 使用する演算子は enum定義 を参照。

array[T]

任意の型 T の配列。要素数は 変数定義時に指定します。 定数に限らず変数も要素数として指定できます。 array[T] は1次元です。

2次元配列については array2[T]を 参照してください。 array[T] をネストして array[array[T]] で2次元とすることも可能です。

制約

以下、 1次元配列 array[T] と2次元配列 array2[T] それぞれに対して分けて説明します:

演算子

説明 例
= 配列同士の代入が可能です。要素数が異なる場合、 実行時エラーとなります。
array[int]: a  = 10              # 要素数は初期値として指定
array[int]: b  = 10
b(3) = 5
a = b                            # 配列の代入
for int: i in 0, a.size-1 do
  put("a(", i, ") = ", a(i), "\n")
end

メンバ

コンストラクタ
init(int size)
全コンテナ共通メンバ
int: size # 1次元配列の要素数
T operator() (int i) # 1次元配列の i 番目の要素の取りだし
固有メンバ
int: row # 2次元配列の行数
int: col # 2次元配列のカラム数

以下、詳細です。

int: array[T].size

説明
要素数を返します。
戻り値
要素数(int型)
例
void: f(array[int]: a)     # 配列の要素数を印字
   put(a.size, "\n")
end

array[int]: X  = 10        # 配列長10の変数 X を定義
array[int]: Y  = 123       # 配列長123の変数 Y を定義
f(X)                       # Xの配列長を印字
f(Y)                       # Yの配列長を印字
SEE ALSO
str.size
list.size

T: array[T].operator()(int i)

説明
i番目の要素を返します。
戻り値
i番目の要素
例
array[int]: a = 10   # 配列(10個の整数変数)を用意
a(3)  = 123          # 3番目に値を代入
put(a(3))            # 3番目を印字
SEE ALSO
str.operator()
list.operator()

array2[T]

2次元配列

演算子

説明 例
= 配列同士の代入が可能です。要素数が異なる場合、 実行時エラーとなります。
array2[int]:  a = (10,10)      # 要素数は初期値として指定
array2[int]:  b = (10,10)
b(3,4) = 5
a = b                            # 配列の代入
for int: i in 0, a.row-1 do
  for int: j in 0, a.col-1 do
    put("a(", i, ",", j, ") = ", a(i,j), "\n")
  end
end

メンバ

コンストラクタ
init (int row, int col) # 2次元配列の初期化
固有メンバ
T: operator() (int: i, j) # 2次元配列 i, j の要素 T へのアクセス
int: row # 2次元配列の行数
int: col # 2次元配列のカラム数

以下、詳細です。

T: array2[T].operator()(int: i,j)

説明
2次元配列上の (i,j)の要素を返します。
戻り値
(i,j)番目の要素
例
array2[int]: a = (10,3) # 2次元配列(10x3個の整数変数)を用意
a(3,2) = 123            # (3,2)上に値を代入

# 全値を印字
for int:i in 0, a.row-1 do
   for int:j in 0, a.col-1 do
      put(a(i,j), " ")  # (i,j)要素の取出し
   end
   put("\n")
end
SEE ALSO
str.operator()
list.operator()

int: array2[T].row

説明
2次元配列の行数を返します。
戻り値
2次元配列の行数
例
array2[int]: a = (3,10)     # row,col = 3,10 2次元配列定義
put(a.row)
SEE ALSO
col

int: array2[T].col

説明
2次元配列のカラム数を返します。
戻り値
2次元配列のカラム数
例
array2[int]: a = (3,10)     # row,col = 3,10 2次元配列定義
put(a.row)
SEE ALSO
row

list[T]

リスト型です。

配列型 array[T] との違いは、array がランダムアクセス a(i) が速い 一方、要素の追加ができないのに対し、list は要素の追加ができるが、 ランダムアクセスは遅い、という点です(下の比較表を参照):

比較項目 配列 array リスト list
ランダムアクセス
operator()(int i)
O(1) (速い) O(n) (遅い)
要素の追加 不可 可

Perl/Ruby の配列は、Alan の array の性質と list の性質の両方を 1つに統合している点で優れていると言えます。
Alan では、現時点では実装の容易さという点で両者を別の型としています。 両者の統合は、Iterator を使ってある程度できないか、と 考えています(がまだ構想段階です)。

制約事項: V0.09 では配列が generic なのに対し、 リストは文字列しかサポートしていません。 (v0.22 で対応)

演算子

(今のところありません)

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
init (list) # コピーコンストラクタ
全型共通メンバ
全コンテナ型共通メンバ
int: size # 要素数
T: operator() (int i) # i番目の要素の取得
固有メンバ
void: add (T: v) # 要素の追加
str: join (str: s) # 要素の連結。文字列のみ対応。
str: join (byte: ch) # (同上)
void: shift # (v0.09) 最初の要素を削除
list[T]: reverse # (v0.09) 逆順のリストを生成
list[T]: sort # (v0.09) alphabet順にソートしたリストを生成
iter[T]: iter # (v0.09) iter[str] (文字列反復子)を生成

以下、詳細です。

list[T].init

説明
デフォルトコンストラクタです。 初期値リストによる初期化などはまだサポートしていません。
例
list[str]: l
put(l)   # 0個の文字列リストを印字します(つまり空)
SEE ALSO
BUG

list[T].init(list[T])

説明
コピーコンストラクタです。
例
list[str]: l = "Hello:World:from:Alan".split(':') # 文字列を':'で区切ったリスト
                                                  # で l を初期化します
put(l); # リストの印字
SEE ALSO
BUG

int: list[T].size

説明
要素数を返します。
戻り値
要素数
例
# 文字列を ':' で区切ったリストの個数を印字
put("Hello:World:from:Alan".split(':').size)
BUG

T: list[T].operator()(int: i)

説明
i番目の要素を返します。
戻り値
i番目の要素
例外
VE_LIST_OUT_OF_IX --添字 i が 0..size-1 を超えた場合
例
list[str]: l = "Hello:World:from:Alan".split(':')
put(l(1), "\n")   # 1番目(0が基準)の要素を印字
put(l(2), "\n")   # 2番目(0が基準)の要素を印字
SEE ALSO
BUG

void: list[T].add(T: v)

説明
要素をリストの最後に追加します。

メモ: メソッドの中で、値を返すものと返さないものがあります。 add(), shift() は返さない仕様となっています。この基準は、 メソッドに渡すもの(例: A.method(B) で言えば A, B)のどれか1つでも:

としています。更に、 関数とできるものでも、 値として返すか自分自身を更新するかのコストを比較し、 手続きとしているケースもあります。list.add() や list.shift() がこのケースです。

が、この使いにくいですね。どうすればよいか、 ご意見ありましたら教えてください。

戻り値
-
例
list[str]: l = "Hello:World".split(':')
l.add("from Alan")
put(l)
SEE ALSO
BUG

str: list[str].join(str: s)
str: list[str].join(byte: ch)

説明
引数 s, ch を結合文字(列)とし、リスト中の全要素を結合し、 1つの文字列とします。
戻り値
結合された文字列
例
# ':' で区切られた文字列を分割し、'/' で結合し直す。
put("Hello:World:from:Alan".split(':').join('/'))
SEE ALSO
BUG

void: list[T].shift

説明
最初の要素を削除します。

リストの最初の要素を削除し、全体を1つ左に シフトするイメージです。

戻り値
-
例
list[str]: l = "Hello:World:from:Alan".split(':')
l.shift
put(l)

list[T]: list[T].reverse

説明
逆順のリストを生成します
戻り値
逆順に生成されたリスト
例
put("Hello:World:from:Alan".split(':').reverse)

list[T]: list[T].sort

説明
alphabet順にソートしたリストを生成します。
戻り値
alphabet順にソートしたリスト
例
put("Hello:World:from:Alan".split(':').sort)

iter[T]: list[T].iter

説明
list の各要素を返す反復子 iter[T] を生成します。
戻り値
list の各要素を返す反復子 iter[T]
例
for str: s in "Hello:World:from:Alan".split(':') do
    put("!", s, "!\n");
end

map(連想配列)型

文字列を添字とする配列です。

Perl/Ruby のハッシュ、awk の連想配列、C++/STL の map、 Python のディクショナリに相当します。

型名に 'map' を選んだのは、

・・・というところです。

型パラメータとして、現在、

・・・をサポートしています。map は、map[str] の省略形と考えてください。 以降、map[T] と言うときは map型(str->str)も含めています。

(v0.10) key に map されるエントリが存在しない場合、 read 時(右辺値)と write 時(左辺値)で振る舞いが異なります。 詳細は operator() を参照下さい。

任意の型 T から別の任意の型 U への連想配列型 map[T,U] は まだサポートしていません。

メンバ

コンストラクタ
init () # デフォルトコンストラクタ
全型共通メンバ
全コンテナ型共通メンバ
int: size # 要素数
T: operator() (str) # 検索
固有メンバ
iter[str]: iter # map[T] 上の全てのキーを返す反復子

以下、詳細です。

map[T].init()

説明
map[T] 型のコンストラクタです。
現バージョンでは、初期値は何もとりません。 つまり、初期値として配列を渡すようなことはまだサポートされていません。 個別に代入してください。
例
map[str]:   m;
map[int]:   n;

m("Hi") = "(^_^)/"
m("Ho") = "(^o^)"
n("Ha") = 123
n("Hu") = 456

put(m("Hi"), "\n")
put(n("Ha"), "\n")
SEE ALSO
TBD
BUG
未定義の添字でアクセスしたときの振る舞いについてバグがあります。 意図しようとしたのは例外を発生することでしたが、現状では デフォルト値(str なら空文字列 "", int なら 0、など)がセット されてしまいます (v0.10 直しました)。

int: map[T].size

説明
要素数を返します。
戻り値
要素数
例
map[str]: m
m("Hi") = "(^_^)"
m("Ho") = "(;_;)"
put(m.size)
SEE ALSO
TBD
BUG
TBD

T: map[T].operator()(str)

説明
文字列を検索キーとして、対応する値を検索します。 map 型の場合は対応する文字列が、map[T]型の場合は対応する型 T の 値が返されます。

(v0.10) key に map されるエントリが存在しない場合、 read 時(右辺値)と write 時(左辺値)で振る舞いが異なります:

戻り値
検索された値
例
map:  m

put(m("Hi")) ||
   put("-")
end
SEE ALSO
TBD
BUG

iter[str]: map[T].iter

説明
キーを要素とする反復子を返します。 反復子の生成するキーの順番は不定です(hashを使用しているので)。
戻り値
キーを要素とする反復子 iter[str]
例
map[str]: m
m("Hi") = "(^_^)"
m("Ho") = "(;_;)"
for str:key in m do
    put("key = ", key, " value = ", m(key), "\n")
end
SEE ALSO
TBD

Top / Alan言語仕様 / データ型





Alan ver0.31