3 Basics

まず最初は、私達が使う Oz のプログラミングスタイルをシーケンシャルなものに制限しましょう。この段階では、あなたは Oz の計算を1つの文(statement)を次々に実行していくシーケンシャルなプロセスとして振る舞うものと考える事が出来ます。私達はこのプロセスを スレッド(thread) と呼びます。スレッドはストア(store)にアクセスします。ストアは中の情報を読み込み、追加、更新する事で操作する事が出来ます。情報は変数(variable)の概念によってアクセスされます。スレッドは、そのスレッドから可視(visible)である変数を通じて情報に直接的にまたは間接的にアクセス出来ます。Oz の変数は単一代入(single-assignment)変数、より適切に言うと論理変数です。CやJavaの様な命令型(imprerative)言語では、変数は複数回代入を行えます。対照的に、単一代入変数は一度のみ代入が行えます。この概念はデータフロー言語と並行論理プログラミング言語を含む多くの言語で知られています。単一代入変数はそのライフサイクルの中でいくつかの段階を持っています。最初、それは未知の値として導入され、後に値を代入される事がありその場合は変数は束縛された(bound)状態となります。一度変数が束縛されると、変更は出来ません。論理変数(logic variable)は他の変数と同一視される事も可能な単一代入変数です。論理変数を使う事は、状態変化を行う事が不可能である、という事を意味しません。なぜなら後で見るように、変数は状態を持つセルに束縛でき、セルの内容は変更可能だからです。

スレッドが以下の文:

local X Y Z in S end

を実行すると、3つの単一代入変数 X, Y, Z が導入され、これらの変数のスコープで文 S が実行されます。変数は通常は大文字(upper-case)の綴りで始まり、それ以降は任意の数の英数字を続ける事が出来ます。変数はバッククォート(`)で囲まれた印字可能な文字列としても表せます。例: `this $ is a variable` S を実行する前、宣言された変数は紐付けられた値を持たないでしょう。この様な変数を未束縛(unbound)と呼びます。Oz プログラムでは、後で見る事になる特定のパターンマッチングが構築するものを除いて、いかなる変数も必ず導入されていなければなりません。

宣言の別の形式:

declare X Y Z in S

これは X, Y, ZS 中の全域で可視になる端が開いた宣言で、S に続く文でも同じ綴りの変数が宣言されて上書きされない限り有効となります。この時、X, Y, Z はグローバル変数となります

3.1Oz の主要な型(type)


Figure 3.1: Oz の型ヒエラルキー


Oz は動的型付けを行う言語です。Figure 3.1 は Oz の型ヒエラルキーを示しています。どの変数も、値を得る時には、これらの型の中からから一つの値に束縛されるでしょう。多分、Chunk, Cell, Space, FDInt, Name を除いて、これらの型のほとんどは経験あるプログラマにはなじみがあるものでしょう。私達はやがてこれら全ての型について論じます。せっかちな読者のためにここでいくつかのヒントを与えます。Chunk(チャンク) データ型はユーザに新しい抽象データ型を導入する事を可能にします。Cell(セル) は状態コンテナと状態変更のプリミティブな概念です。Space(空間) は探索のテクニックを使って進んだ問題を解くのに必要となります。FDInt は制約プログラミングと制約充足によく使われる有限ドメインの型です。Name(名前) は偽造出来ない匿名トークンを導入します。

言語が動的型付けである、というのは変数が導入された時にはその型は値と同様に未知である、という意味においてです。変数が Oz の値に束縛された時のみ、その型は決定されたものになります。

3.2情報を追加する

Oz において、ストアに情報を追加する、言い換えると変数を値に束縛するのにはいくつかの手段があります。最もよく使われる形式は等価(equality)中置演算子(infix operator)である = を使う事です。例として、変数 X が以下の様に宣言されて与えられた場合:

X = 1

これは未束縛の変数 X を整数 1 に束縛し、この情報をストアに追加します。今、もし X が既に値 1 に束縛されているのであれば、この操作は X に対するテストとして振る舞います。もし X が既に整合性の無い値(1以外の値)に束縛されているとすると、適切な例外(exception)が発生します(be raised)。例外制御は後で記述されています。

3.3構造同等性(structual equality)とデータ型(data type)

Figure 3.1NumberRecord から始まるヒエラルキーは、Oz のデータ型についてそのメンバー(値)が等しいのはそれらが構造的に類似である時のみであると定義しています。例えば2つの数値はそれらが同じ型、もしくは一方が他方のサブ型で、値が等しい場合に等価です。例えば、両者が integer で同じ数値であるか、両者がリストでそれらの head 要素が同じで続く tail もそれぞれ同じである場合です。構造同等性は、値が物理メモリ中で別の位置に存在するレプリカであった場合でも等価であるという事を許します。

3.4数値(number)

以下のプログラムは3つの変数 I,F, C を導入します。I は整数(integer)に、F は浮動小数(float)に、C は文字(character) t にこの順序で紐付けます。それから I,F, C を含むリストを表示します。

local I F C in 
   I = 5
   F = 5.5
   C = &t 
   {Browse [I F C]}
end

Oz は2進(binary)、8進(octal)、10進(decimal)、16進(hexadecimal)表記を整数用にサポートしており、それらは任意の大きさを持つ事が出来ます。8進表記は頭が 0 で始まり、16進表記は頭が 0x0X で始まります。浮動小数は整数とは違い、小数点を持たなければなりません。浮動小数の他の例は ~ が負を表す単項演算子である事に見られます:

~3.141   4.5E3    ~12.0e~2

Oz では、自動的な型の変換は無いので、5.0 = 5 は例外を発生させるでしょう。当然、明示的な型の変換を行うプリミティブな手続きがあります。これらとその他多くが [Shu98] で見る事が出来ます。文字は整数のサブ型で、0, ..., 255 までの範囲のものとなっています。Unicode ではなく ISO 8859-1 が使われています。印字可能な文字は外部表現(external representation)を持ち、例えば &0 は実際には整数 48&a97 です。いくつかの制御文字は同様に外部表現を持っています。例: &\n は改行。全ての文字は &\ooo として記述できます(o は8進数)。

文字、整数、浮動小数の操作はライブラリモジュール Char, Float, Int で目にする事が出来ます。付加されるジェネリックな操作はモジュール Number で目にする事が出来ます。

3.5リテラル(literal)

他の重要な原始型(atomic type)、すなわちそのメンバーが内部表現を持たないものは、リテラルのカテゴリーに属します。リテラルはアトム(atom)と名前(name)に分けられます。アトムは、小文字(lower-case)の綴りで始まる英数字の文字列、もしくはクォート(')で囲まれた任意の印字可能な文字列から作られた記号的(symbolic)なエンティティです。例:

a   foo   '='   ':='   'OZ 3.0'   'Hello World'

アトムは辞書式の順序を持っています。

他の基礎的なエンティティは名前(Name)です。名前を作る唯一の手段は、手続き {NewName X} を呼び出す事で、ここで X が世界でただ一つと保証された新しい名前に紐付けられます。名前は偽造も表示も出来ません。後で見るように、名前は Oz プログラムのセキュリティで重要な役目を果たします。Name のサブ型 Bool は予約されたキーワード truefalse を持つ再定義から保護された2つの名前から成っています。それゆえ、ユーザのプログラムはそれらを再定義出来ず、それらの再定義をあてにした全てのプログラムは使い物になりません。型 Unit は単一の名前 unit から成ります。これは多くの並行プログラムにおいて同期トークンとして使われます。

local X Y B in 
   X = foo
   {NewName Y}
   B = true 
   {Browse [X Y B]}
end

3.6レコード(record)とタプル(tuple 組)

レコードは構造的に合成されたエンティティです。レコードはラベル(label)と決まった数のコンポーネントか引数を持ちます。可変引数を取るオープンレコード(open record)と呼ばれるレコードもあります。今は、'closed'なレコードに限定しましょう。以下がレコードとなります:

tree(key: I value: Y left: LT right: RT)

4つの引数を持ち、そのラベルは tree です。それぞれの引数はフィールド名:フィールド(Feature:Field)の組から成り、上のレコードでは key, value, left, right がフィールド名となります(訳注:featureをフィールド名としたのはCTMCP邦訳版にならいました)。対応するフィールドは変数 I,Y,LT, RT です。レコードの特徴を抜かす事も可能で、その場合には論理プログラミングにおける合成項として知られているものになります。Oz では、これはタプル(tuple)と呼ばれます。以下のタプルは同じラベルと上のレコードと同じフィールドを持ちます:

tree(I Y LT RT)

これはレコードのための構文表記に過ぎません:

tree(1:I 2:Y 3:LT 4:RT)

ここでフィールド名は 1 から始まってタプルの数までの数値です。以下のプログラムは、1つはレコードでもう一つは同じラベルとフィールドを持つタプルから成る2つの要素を表示するものです。

declare T I Y LT RT W in 
T = tree(key:I value:Y left:LT right:RT)
I = seif
Y = 43
LT = nil
RT = nil
W = tree(I Y LT RT)
{Browse [T W]}

表示:

[tree(key:seif value:43 left:nil right:nil)
 tree(seif 43 nil nil)]

3.7レコードの操作

レコードにおけるいくつかの基本的な操作を論じます。ほとんどの操作はモジュール Record で目にする事が出来ます。レコードコンポーネントのフィールドを選択するために、私達は中置のドット演算子を使います。例えばRecord.Feature

% コンポーネントを選択
{Browse T.key}
{Browse W.1}
% seif が二度 browser に表示されるでしょう
seif
seif

レコードの引数(arity)はレコードのフィールド名を辞書順にソートしたものです。レコードの引数を表示するには手続き Arity を使います。手続き適用 {Arity R X}R がレコードに束縛されると、X をレコードの引数に束縛します。以下の文を実行すると

% レコードの引数を取得
local X in {Arity T X} {Browse X} end 
local X in {Arity W X} {Browse X} end

以下を表示するでしょう

[key left right value]
[1 2 3 4]

他の有用な操作はレコードのフィールドの条件付き選択です。操作 CondSelect はレコード R、フィールド名 F、それとデフォルトのフィールド値 D を取り、引数 X を結果として返します。特徴 FR に存在すれば、XR.F に束縛され、そうでなければ X はデフォルトの値 D に束縛されます。CondSelect はプリミティブな操作ではありません。それは Oz で定義可能です。以下の文:

% 条件によりコンポーネントを選択する
local X in {CondSelect W key eeva X} {Browse X} end 
local X in {CondSelect T key eeva X} {Browse X} end

以下を表示するでしょう

eeva
seif

Oz で使われる共通の中置のタプル操作演算子は # です。1#2 は2要素のタプルで、1#2#3 は3要素のタプル:

'#'(1 2 3)

であって、ペア(pair 2要素タプルのこと) 1#(2#3) ではありません。# 演算子では、1要素のタプルを直接書く事は出来ません。代わりに、通常の前置のレコード構文に戻りましょう: 空のタプルは '#'() または '#'、そして1要素のタプルは '#'(X) と書かれなくてはいけません。

操作 {AdjoinAt R1 F X R2}R2R1 の特徴 F にフィールド X を結合した結果と束縛します。R1 が既にフィールド名 F を持っていれば、結果のレコード R2R1.FX となっている事を除けば R1 と同じ物です。それ以外では、R2 で返ってくる結果は引数 F:XR1 に加えられたものになります。

操作 {AdjoinList R LP S} はフィールド名-フィールドのペアのリストから成るレコード R を取り、S で次の様な新しいレコードを返します:

この操作は当然 AdjointAt を使って定義されます。

local S in  
   {AdjoinList tree(a:1 b:2) [a#3 c#4] S}
   {Show S}
end 
% 結果は S=tree(a:3 b:2 c:4)

3.8リスト(list)

Scheme や Prolog の様な多くの他の記号的プログラミングでの様に、list 形式は Oz におけるデータ構造の重要なクラスです。Oz ではリストのカテゴリは単一のデータ型に属しているわけではありません。それらはむしろ概念的な構造です。リストはアトム nil によって表現される空のリストか、中置演算子 | とリストの頭部(head)と尾部(tail)である2つの引数を取るタプルです。それゆえ、最初の3つの正の整数のリストは次の様に表現されます:

1|2|3|nil

別の便利な特別な表記法は閉じたリスト(closed list)です。すなわち決まった要素数のリスト:

[1 2 3]

上の表記法は閉じたリストにしか使われず、最初の2要素は 12 ですが、その尾部は変数 X で次の様に見えます:

1|2|X

標準的なレコードの表記法をリストのために使う事も出来ます:

'|'(1 '|'(2 X))

文字コードに対応した要素のリストにはさらなる表記法の亜種が許されます。この表記法は文字列(string)と呼ばれます。例として

"OZ 3.0"

はリスト

[79 90 32 51 46 48]

であり、以下と等しいです。

[&O &Z  &3 &. &0]

3.9仮想文字列(virtual string)

仮想文字列は仮想的な結合(concatenation)をされた文字列として表現される特別なタプルです。その結合は実際に必要になった時に行われます。仮想文字列はファイル、ソケット、ウィンドウによって I/O のために使われます。nil'#' を除く、数値、文字列、'#'でラベル付けられたタプルの様な全てのアトムは仮想文字列を構成出来ます。ここに一例を示します:

123#"-"#23#" is "#100

これは下の文字列を表現します

"123-23 is 100"

注意:このセクションで論じた各データ型は、Mozart システムのモジュールに対応しています。それらのモジュールはデータ型に対応した操作を定義しています。あなたはより多くのこれらの操作に関する事を The Oz Base Environment documentation で見る事が出来ます。


Seif Haridi and Nils Franz�n
Version 1.4.0 (20080704)