Amber

A Language for High-Level Programming with Self-Extension

チュートリアル3: 基本的なオブジェクトの種類

今後、Amberが扱うデータをオブジェクトと呼ぶことにします。 オブジェクト指向で言う所のオブジェクトとは異なるので注意して下さい。 「計算・処理の対象」くらいの意味です。

Amberの扱うオブジェクトには アトム複合オブジェクト の2種類があります。

アトム

アトムとはAmberがあらかじめ用意している最も原始的なデータの種別で以下のような種類が存在します。

文字列

シングルクオート'またはダブルクオート"で文章を囲むと文字列オブジェクトとして解釈されます。ダブルクオートで囲んだ場合にはエスケープシーケンスが解釈され、シングルクオートの場合には解釈されません。

amber:1> puts("Hello\n")
Hello

=> nil
amber:2> puts('Hello\n')
Hello\n
=> nil

標準ライブラリには文字列を操作する関数がいくつか用意されています。例えば以下のようにして文字列を連結する事が出来ます。

amber:1> "Hello" + " " + "World" + "!"
=> "Hello World!"

詳しくは標準ライブラリ:文字列を参照して下さい。

なお、Amberは文字を表すオブジェクトは持っておらず、単一の文字は長さ1の文字列として表現します。例えばi番目の文字を取り出す演算(演算子[])を行なってみると

amber:1> "Hello"[2]
=> "l"

という様に長さ1の文字列が返ってきます。 また、現状のAmberは多バイト文字をサポートしておらず、Ascii文字列のみが使用可能です。

シンボル

アルファベット、アンダースコア_、数字を並べて書くとシンボルとして解釈されます。ただし先頭を数字から始める事はできません。 Amberのシェルにシンボルをただ入力すると、それは変数を表していると解釈されます。例えば以下の様に単にxと入力すると、システムにはxという名前の変数がまだ定義されていない為にエラーとなります。

amber:1> x
Error: UndefinedVariable{[amber:1], x}

そこで、単なるオブジェクトとしてのシンボルを作成する場合には以下の様にバックスラッシュ\に続けて入力します。

amber:1> \x
=> x

バックスラッシュはクォーテーションを表しています。通常、Amberは入力されたオブジェクトをプログラムとして解釈しますが、クォーテーションが行われている場合には入力されたオブジェクトそのものとして解釈を行います。クォーテーションについては後の回にまた説明します。

シンボルを処理する関数もいくつか用意されています。詳しくは標準ライブラリ:シンボルを参照して下さい。

特殊シンボル

上で述べた様にAmberはシンボルを変数として解釈しますがtrue, false, nil, undefの4つのみはそのシンボル自身として解釈します。

amber:1> true
=> true
amber:2> false
=> false
amber:3> nil
=> nil
amber:4> undef
=> undef

truefalseは真偽値を表しています。例えば比較命令などがこれらを返します。

amber:1> 1 < 2
=> true
amber:2> 1 == 2
=> false

nilは無という意味で、特に意味が無い値を表す為に用います。例えば関数putsの戻り値はnilです。

amber:1> puts("Hello World!")
Hello World!
=> nil

undefは未定義という意味で、参照された要素が存在しない事を表す為に用います。例えば、この後説明する連想配列を存在しないキーで参照するとundefが返ります。

amber:1> Table{"one" => 1, "two" => 2}
=> Table{"one" => 1, "two" => 2}
amber:2> %["three"]
=> undef

整数

整数値を入力すればそのまま整数として解釈されます。0b0o0xなどを先頭に付ければそれぞれ2進法・8進法・16進法による整数値として解釈されます。

amber:1> 123
=> 123
amber:2> 0b101
=> 5
amber:3> 0o777
=> 511
amber:4> 0xabcd
=> 43981

通常の四則演算などの計算が出来ます。

amber:1> 1 + 2
=> 3
amber:2> 1 - 2
=> -1
amber:3> 2 * 3
=> 6
amber:4> 7 / 3
=> 2
amber:5> 7 % 3
=> 1
amber:6> 2^3
=> 8

整数同士の除算(演算子/)は結果の切り捨てを行います。演算子%は剰余算、演算子^は累乗算を表します。詳しくは標準ライブラリ:整数を参照して下さい。

固定長整数と多倍長整数

Amberの整数はデフォルトでは固定長整数であり、有限範囲の整数値しか表せません。固定長整数の範囲はINTEGER_MIN以上INTEGER_MAX以下です。現状では以下のような値になっていますが、実装により変化する可能性があります。

amber:1> INTEGER_MIN
=> -1073741824
amber:2> INTEGER_MAX
=> 1073741823

計算結果がこの範囲外となった場合にはオーバーフローし、誤った値となります。 デフォルトの動作ではオーバーフローの検出などは行いません。

Amberは多倍長整数も備えています。多倍長整数を使用する場合にはopen文を利用します。 (open文については後の回で詳しく扱います。)

amber:1> open BigInt
=> nil
amber:2> 7^160
=> 1643184774938171857917000410556544806341837419599523497069764671233207565562287891877564323818254449486910838997871467298047369612896001

open BigIntの実行後は固定長整数と多倍長整数の間の変換は自動的に行われます。(メモリに収まる範囲内で)任意の大きさの整数を用いた計算を行う事が可能になります。

浮動小数点数

小数点’.’を含む数値を入力すれば浮動小数点数となります。 浮動小数点数の内部表現は現状ではC言語のdouble型と同じです。 整数と同様に四則演算などを行う事が出来ます。

amber:1> 1.2
=> 1.2
amber:2> 3.14^2
=> 9.8596

詳しくは標準ライブラリ:浮動小数点数を参照して下さい。

複合オブジェクト

既存のオブジェクトを組み合わせて複合オブジェクトを作成する事が出来ます。 Amberがあらかじめ用意している複合オブジェクトには以下のような種類があります。 これらは特にコンテナと呼ばれ様々なオブジェクトを格納する為に用いる汎用なデータ構造です。

リスト

[]で囲んで式を列挙するとリストが出来ます。

amber:1> [1,2,3]
=> [1,2,3]
amber:2> ["foo", "bar", "baz"]
=> ["foo", "bar", "baz"]
amber:3> [1, "foo", [1,2,3]]
=> [1, "foo", [1, 2, 3]]

3番目の例のように異なる種類のオブジェクトも格納する事が出来ます。 演算子([])でi番目のオブジェクトの読み取り、演算子([]=)で書き換えが出来ます。

amber:1> [1, "foo", [1,2,3]]
=> [1, "foo", [1, 2, 3]]
amber:2> %1[0]
=> 1
amber:3> %1[1]
=> "foo"
amber:4> %1[2]
=> [1, 2, 3]
amber:5> %1[1] = "bar"
=> "bar"
amber:6> %1
=> [1, "bar", [1, 2, 3]]

標準ライブラリには2つのリストの連結、リストの並べ替えなどの関数が用意されています。

amber:1> [1,2,3] + [4,5,6] + [7,8,9]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

リストはAmber内部ではシングルリンクリストとして実現されています。 連結したり分割したり要素を順番に巡回するような用途には適していますが、i番目を直接取り出すような操作には適していません。

詳しくは標準ライブラリ:リストを参照して下さい。

配列

Array{ .... }の様に記述すると配列を作る事が出来ます。

amber:1> Array{1, 2, 3}
=> Array{1, 2, 3}
amber:2> Array{"foo", "bar", "baz"}
=> Array{"foo", "bar", "baz"}
amber:3> Array{1, "foo", [1,2,3]}
=> Array{1, "foo", [1, 2, 3]}

リストと同様に演算子[]と演算子[]=によってi番目の要素の読み書きを行います。リストに比べてi番目を直接読み書きする操作が高速(定数時間)ですが、一方連結・分割や長さの変更には余分なメモリ・時間を要します。

詳しくは標準ライブラリ:配列を参照して下さい。

タプル

()で囲めばタプルとなります。

amber:1> (1,2,3)
=> (1,2,3)
amber:2> ("foo", "bar")
=> ("foo", "bar")
amber:3> (1, "foo", [1,2,3])
=> (1, "foo", [1, 2, 3])

各要素へのアクセスはリスト・配列と同様に演算子[]と演算子[]=で行います。

タプルは少数のオブジェクトの組を作りたい場面に用います。例えば関数から複数の戻り値を返したい場合などに役に立ちます。 タプルはリストや配列のように長さを変更したり、要素を並べ替えるといったオブジェクトの列としてとしての機能は備えていない代わりにとても軽量なデータ構造です。

詳しくは標準ライブラリ:タプルを参照して下さい。

連想配列

以下の様にTable{...}で囲み=>で結んだ要素を列挙すると連想配列が出来ます。

amber:1> Table{"one" => 1, "two" => 2, "three" => 3}
=> Table{"one" => 1, "two" => 2, "three" => 3}

連想配列では番号の代わりに記号=>の左に書いたキーを用いて値を読み書きする事が出来ます。キーには任意のオブジェクトを利用する事が出来ます。読み書きは他のコンテナと同様に演算子[][]=を用います。

amber:1> Table{"one" => 1, "two" => 2, "three" => 3}
=> Table{"one" => 1, "two" => 2, "three" => 3}
amber:2> %1["one"]
=> 1
amber:3> %1["two"]
=> 2
amber:4> %1["three"]
=> 3
amber:5> %1["four"] = 4
=> 4
amber:6> %1
=> Table{"one" => 1, "two" => 2, "three" => 3, "four" => 4}

詳しくは標準ライブラリ:連想配列を参照して下さい。