Section 1. データとデータ型

1.1 データ

XDuceでは、文字列、整数、浮動小数点数、要素、属性といった種類のデータを扱います。

1.1.1 文字列

ダブルクォートで囲まれた文字列は、文字列として扱われます。

let val _ = print("Hello World!!")
  (* "Hello World!!" を印字 *)

let val _ = print("X" ^ "Duce")
  (* "XDuce" を印字 *)

1.1.2 整数

オプションのハイフンと、続く数字列は、整数として扱われます。

let val _ = print(1);
  (* 1を印字 *)

let val _ = print(2001 - 2006);
  (* -5を印字 *)

1.1.3 浮動小数点数

オプションのハイフンと、続くドットを1つ含んだ数字列は、浮動小数点数として扱われます。

let val _ = print(3.14159265359)
  (* 3.14159265359を印字 *)

let val _ =  print(1. /. .5) 
  (* 2.を印字 *)

1.1.4 要素

ラベルと、続く大括弧で囲まれたデータは、要素として扱われます。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'[]
  (* 予約語や特殊文字をラベルにしたければ、シングルクォートで囲む *)

1.1.5 データ列

コンマでつないだデータは、データ列として扱われます。

let val d = strong["hoge"], em["foo"], "bar"
  (* <strong>hoge</strong><em>foo</em>bar に対応 *)

1.1.6 属性

@に続くラベルと、続く大括弧で囲まれたデータは、属性として扱われます。XMLの属性に対応します。

let val d = @lang["en"]
  (* データが"en"でラベルがlangの属性;
     XML の属性 lang="en" に対応 *)

let val d = p[@lang["en"], "hoge"]
  (* <p lang="en">hoge</p> に対応 *)

一つのデータ列に現れる属性には、順序は関係しません。また一つのデータ列に同じラベルが現れてはいけません。

1.1.7 名前空間

ラベルの名前が衝突しないように、名前空間を宣言、使用できます。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"]
  (* デフォルトの名前空間を使用 *)

1.2 データ型

1.2.1 正規表現型

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度以下の出現を表します。正規表現に似ているため正規表現型と呼びます。

1.2.2 型強制

単に安全でない代入をしようとすると、型検査時にエラーになります。安全でない代入をするためには、validate構文を使います。ラインタイム時に変換を試み、できなければ評価時にエラーになります。

let "bar" as bar = validate "foo" with "bar"
  (* 文字列 "bar" 型の変数 bar に文字列 "foo" を検査して代入;
     評価エラー *)

1.2.3 型定義

型に名前を付けられます。

type foo_t = "foo"
  (* foo_t 型を定義 *)

let foo_t as foo = "foo"
  (* foo_t 型、すなわち文字列 "foo" 型の変数 foo に文字列 "foo" を代入 *)

さらに、再帰にできます。

type nest_t = nest[nest_t] | ()
  (* 任意の回数ネストできる要素 *)

1.2.4 定義済みの型

1.2.4.1 String

任意の文字列型です。

let String as d = "hoge"
  (* 文字列型の変数 d に文字列 "hoge" を代入 *)

1.2.4.2 Int

任意の整数型です。疑似的には、次のように定義されていると考えるといいでしょう。

type Int = 0 | 1 | -1 | 2 | -2 | 3 | -3 | 4 | -4 | ...

1.2.4.3 Float

任意の浮動小数点数型です。

1.2.4.4 ~ / @^

任意の要素/属性を表します。

let @~["en"] as d = @lang["en"]

1.2.4.5 ^ / @^

指定されたラベルを除く、任意の要素/属性を表します。

let ^object[@lang["en"]] as d = p[@lang["en"]]

1.2.4.6 @..

指定されたラベルを除く、任意の属性型です。

let @.. as d = @lang["en"]
  (* 型検査エラーにならない *)

let @lang["ja"] | @.. as d = @lang["en"]
  (* 型検査エラーになる *)

1.2.4.7 AnyAttrs

任意の属性型です。

let AnyAttrs as d = @lang["en"]
  (* 型検査エラーにならない *)

let @lang["ja"] | AnyAttrs as d = @lang["en"]
  (* 型検査エラーにならない *)

1.2.4.8 AnyElm

任意の要素類型です。次のように定義されていると考えるといいでしょう。

type AnyElem = Int | Float | String | ~[AnyAttrs, AnyElem*]

1.2.4.8 AnyElms

任意の要素類型です。次のように定義されていると考えるといいでしょう。

type AnyElems = AnyElem*

1.2.4.9 Any

任意の型です。次のように定義されていると考えるといいでしょう。

type Any = (Int | Float | String | AnyAttrs | AnyElems)*

1.2.5 型推論

型をわざわざ指定しなくとも、コンパイラが推論して限定されます。

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" 型の変数に代入可能 *)

1.2.6 型変数

定義時には汎用的に規定しておきたいが、使用時には限定したい場合に、型を決めうちにしない方法が使えます。

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に限定 *)

1.2.7 DTDによる型宣言

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