XDuceでは、文字列、整数、浮動小数点数、要素、属性といった種類のデータを扱います。
ダブルクォートで囲まれた文字列は、文字列として扱われます。
let val _ = print("Hello World!!") (* "Hello World!!" を印字 *) let val _ = print("X" ^ "Duce") (* "XDuce" を印字 *)
オプションのハイフンと、続く数字列は、整数として扱われます。
let val _ = print(1); (* 1を印字 *) let val _ = print(2001 - 2006); (* -5を印字 *)
オプションのハイフンと、続くドットを1つ含んだ数字列は、浮動小数点数として扱われます。
let val _ = print(3.14159265359) (* 3.14159265359を印字 *) let val _ = print(1. /. .5) (* 2.を印字 *)
ラベルと、続く大括弧で囲まれたデータは、要素として扱われます。XMLの要素に対応します。
let val d = title["hoge"] (* データが"hoge"でラベルがtitleの要素; XMLの要素 <title>hoge</title> に対応 *) let val d = head[title["hoge"]] (* データが、ラベルがtitleでデータが"hoge"の要素で、 ラベルがheadの要素; XMLの要素 <head><title>hoge</title></head> に対応 *) let val d = br[] (* データが空でラベルがbrの要素; XMLの要素 要素<br />に対応 *) let val d = 'val'[] (* 予約語や特殊文字をラベルにしたければ、シングルクォートで囲む *)
コンマでつないだデータは、データ列として扱われます。
let val d = strong["hoge"], em["foo"], "bar" (* <strong>hoge</strong><em>foo</em>bar に対応 *)
@に続くラベルと、続く大括弧で囲まれたデータは、属性として扱われます。XMLの属性に対応します。
let val d = @lang["en"] (* データが"en"でラベルがlangの属性; XML の属性 lang="en" に対応 *) let val d = p[@lang["en"], "hoge"] (* <p lang="en">hoge</p> に対応 *)
一つのデータ列に現れる属性には、順序は関係しません。また一つのデータ列に同じラベルが現れてはいけません。
ラベルの名前が衝突しないように、名前空間を宣言、使用できます。XMLの名前空間に対応します。
namespace html = "http://www.w3.org/1999/xhtml" (* 名前空間 html を宣言 *) let val d = html:title["hoge"] (* 名前空間 html を使用 *)
また、デフォルトの名前空間があります。
namespace = "http://www.w3.org/1999/xhtml" (* デフォルトの名前空間を宣言 *) let val d = title["hoge"] (* デフォルトの名前空間を使用 *)
XDuceでは、各変数にデータ型があり、制約がかけられます。
let "foo" as foo = "foo" (* 文字列 "foo" 型の変数 foo に文字列 "foo" を代入 *) let "bar" as bar = "foo" (* 文字列 "bar" 型の変数 bar に文字列 "foo" を代入; 型検査エラーになる *) let 0 as zero = 1 (* 型検査エラーになる *) let strong["bar"] as bar = strong["foo"] (* 型検査エラーになる *)
制約の厳しい型の変数から緩やかな型の変数への代入は、安全にできます。
let "foo" | "bar" as foobar = "bar" (* 文字列 "foo" または文字列 "bar" 型の変数 foobar に文字列 "bar" を代入; 型検査エラーにならない *)
この検査を、網羅性検査といいます。
説明が前後しますが、型をつなぐ'|'は選択を表します。また、型の後ろに'*'をつけると、任意の回数の反復を表します
let strong["foo" | "bar"]* as foo = strong["foo"], strong["bar"], strong["foo"]
同様に'+'をつけると1度以上の反復、'?'をつけると1度以下の出現を表します。正規表現に似ているため正規表現型と呼びます。
単に安全でない代入をしようとすると、型検査時にエラーになります。安全でない代入をするためには、validate構文を使います。ラインタイム時に変換を試み、できなければ評価時にエラーになります。
let "bar" as bar = validate "foo" with "bar" (* 文字列 "bar" 型の変数 bar に文字列 "foo" を検査して代入; 評価エラー *)
型に名前を付けられます。
type foo_t = "foo" (* foo_t 型を定義 *) let foo_t as foo = "foo" (* foo_t 型、すなわち文字列 "foo" 型の変数 foo に文字列 "foo" を代入 *)
さらに、再帰にできます。
type nest_t = nest[nest_t] | () (* 任意の回数ネストできる要素 *)
任意の文字列型です。
let String as d = "hoge" (* 文字列型の変数 d に文字列 "hoge" を代入 *)
任意の整数型です。疑似的には、次のように定義されていると考えるといいでしょう。
type Int = 0 | 1 | -1 | 2 | -2 | 3 | -3 | 4 | -4 | ...
任意の浮動小数点数型です。
任意の要素/属性を表します。
let @~["en"] as d = @lang["en"]
指定されたラベルを除く、任意の要素/属性を表します。
let ^object[@lang["en"]] as d = p[@lang["en"]]
指定されたラベルを除く、任意の属性型です。
let @.. as d = @lang["en"] (* 型検査エラーにならない *) let @lang["ja"] | @.. as d = @lang["en"] (* 型検査エラーになる *)
任意の属性型です。
let AnyAttrs as d = @lang["en"] (* 型検査エラーにならない *) let @lang["ja"] | AnyAttrs as d = @lang["en"] (* 型検査エラーにならない *)
任意の要素類型です。次のように定義されていると考えるといいでしょう。
type AnyElem = Int | Float | String | ~[AnyAttrs, AnyElem*]
任意の要素類型です。次のように定義されていると考えるといいでしょう。
type AnyElems = AnyElem*
任意の型です。次のように定義されていると考えるといいでしょう。
type Any = (Int | Float | String | AnyAttrs | AnyElems)*
型をわざわざ指定しなくとも、コンパイラが推論して限定されます。
let "foo" | "bar" as foobar = "foo" (* 文字列 "foo" または文字列 "bar" 型の変数 foobar に文字列 "bar" を代入 *) let "foo" as foo = foobar (* 文字列 "foo" 型の変数 foo に foobar を代入; foobar は必ず "foo" であり型安全 *)
したがって、通常は型名を略記できます。
let val d = "foo" (* let Any as d = "foo" と同義; 型推論されるので文字列 "foo" 型の変数に代入可能 *)
定義時には汎用的に規定しておきたいが、使用時には限定したい場合に、型を決めうちにしない方法が使えます。
type map_t = entry[key[String], val[ty X]] (* 定義時にはvalのデータ型は汎用的に規定 *) let map_t{{X -> String}} as map = entry[key["foo"], value[3]], entry[key["bar"], value[7]] (* 使用時にはvalのデータ型はStringに限定 *)
DTDでデータ型がすでに定義されている場合、XDuceの再定義の必要なしに、そのまま使用できます。
import_dtd (prefix="HTML_" namespace="http://www.w3.org/1999/xhtml") "xhtml1-strict.dtd" (* xhtml1-strict.dtd で定義されているデータ型を XDuce で使用 title要素のデータ型名がHTML_titleというふうになる *)
しかし、DTDの性質上、名前空間の対応が不完全で問題があります。
平野貴仁 hiranotaka%zng.info