このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

Catyの型システムとサイト自動生成 (2)

いよいよサイト自動生成の話。

サイトを構成するページの作成をデザイナに依頼することを想定する。静的ページはコンテキストがvoidのテンプレートと考えられるので、すべてのページをテンプレートと考えてよい。

デザイナは、作成するテンプレート(静的ページ含む)の仕様を渡されて作業をする。仕様にはコンテキスト型の記述が含まれるが、コンテキスト型とテンプレートが1:1対応しているわけではない。ハイパーリンクグラフのabstractではない状態ノードとテンプレートが1:1対応する。

  • 具体状態ノード ←→ テンプレート (1:1対応)

具体状態ノードは、型とリンク記述からなる。

  • 具体状態ノード = (型 + リンク記述)

リンク記述まで含めた型概念をハイパー型と呼び、それに対するハイパースキーマハイパーバリデーションの概念があるのだが、完全な定式化ができてないので、具体的状態ノードの型(ハイパーリンクは省略)を中心に話をする。(たぶん、ハイパー型とはハイパーリンクグラフの仕様となるだろう。)

状態ノードと型とテンプレート

S, Tなどは型として、状態ノードを α::S、β::T などと書く。α、βなどはノードの名前(ラベル)である。α≠β(名前が違う)とき、α::T と β::T は別なノードとなる。状態ノードの型は、その状態(画面、ページ)を生成するテンプレートのコンテキスト型と考えてよい(正確に言えばちょっと違うが)。

同じ型Tを持つ2つの状態 α::T と β::T に異なるテンプレートが必要となるのは、αとβのサイト内での役割/用途/文脈などが違うためである(それゆえに違うラベルを与えている)。その違いを示すために異なるデザインにするかも知れない。しかし、これは知的な話なので、非知的な自動生成では、型とテンプレートを対応付けてしまう。α::T と β::T のテンプレートは、内容は同じで名前だけが違うモノとなる。

以上の純化により、テンプレート作成作業とは:

  • 与えられた型(状態の型=コンテキスト型)1つに対して、1つのテンプレート(静的ページを含む)を作る。
  • 一般にN個の型(N≧1)が与えられるので、テンプレートもN個となる。
  • サブテンプレートやテンプレート関数も含めると、N個とは限らないが、これは単に数え方の違いに過ぎない。アクションから直接呼ばれるトップレベルテンプレートはN個である。

型からのテンプレート生成

Ψ、Φなどのギリシャ大文字は型の有限集合を表すことにする。ギリシャ大文字を使った理由は、型やインスタンスと区別するためである。型の有限集合が「スキーマ=仕様」に対応する。T∈Ψ に対して、Tに対応するテンプレートを a(T) とする。aがデザイナによる作業を表す。作業aを人間ではなくて、プログラムにautoでやらせるのが目標。

コンテキスト型がTであるテンプレートテキストの全体を TemplTextT、または TemplText<T> と書くことにする、T=void ならば静的ページを意味する。。多相型 ∀X.TemplText<X> = forall<X>TemplText<X> を、ワイルドカードを使って TemplText*、または TemplText<*> とも書く。

テンプレートを生成する作業は、a:Type→TemplText<*> という写像となる。次の条件を満たす必要がある。

  • a(T)∈TemplText<T>

これは、「型Tに対するテンプレートのコンテキスト型はTであるべき」という当たり前の条件。この条件をコンテキスト条件と呼ぶことにする。

テンプレート展開のevalであるexpandを使うと、f(t) := expand(t, a(T)) として、写像 T→Text を定義できるので、a(T) は指数型 [T, Text]に入ると思ってもよい。つまり、aは、(Type → [*, Text]) という写像とも解釈できる。ただし、aがType全域で定義されいるとは限らないので、部分写像と考える。

一般に、コンテキスト条件を満たす Type→TemplText* という写像は「型からテンプレートを生成する操作」なので、サイト自動生成に使える。ただし、与えられた仕様(型の有限集合)とマッチしなくてはならない。

  • 部分写像 a:Type→TemplText* がΨ(Ψ⊆Type)と適合するとは、Ψ⊆(aの定義域) のこと。

レイフィケーション

Typeは普遍データ領域Uの外側にある。Type→U という埋め込みを型レイフィケーションと呼ぶ。型レイフィケーションも全域でなくて(部分レイフィケーションで)もよいし、いくつかのレイフィケーションがあってもよい。なにか標準的なレイフィケーションを1つ選んで、それをReiとする。Rei:Type→U (埋め込み写像)。

a:Type→TemplText* に対して、次の性質を満たすa'を考える。

  • T∈Type に対して、a'(Rei(T)) = a(T) が(両辺が定義されるなら)成立する

a'は、Uの外に存在するaをU内に落としたもの。a' は U→TemplText* だが、TemplText*⊆Text なので、a':U→Text という部分写像と考えてよい。a'は次の性質を持つ。

  1. Uの適当な部分集合上で定義されている。
  2. 値はテキストである。

つまり、なんてことないコマンドである。a'をメタレベルで解釈しなおすと、a:Type→TemplText* という高階写像となる。

高階テンプレートとレイフィケーション

型からテンプレートを生成する機能であるaを定義する際に、再びテンプレート技術を使うことができる。このとき使うテンプレートは、次の意味で高階である。

  • コンテキスト(入力)がTypeの要素なので、高階の対象を入力とする。
  • 結果(出力)が、指数型 [T, Text]とみなせるので、出力も高階の対象である。

「高階の対象」という言葉を使ったが、入力は「集合(型)の集合」、出力は関数型(指数型)である。レイフィケーションを使うことにより、aをa'に落とせる。a'を定義するテンプレートでは:

  • コンテキスト(入力)はUの要素なので、単なるデータである。(意味は高階の対象だが。)
  • 結果(出力)はTextなので、単なるテキストデータである。(テンプレートテキストである必要があるが。)

「集合の集合」に「関数」を対応させる、という高階の写像aも、レイフィケーションを通じて、単なるテンプレートa'で実現できる。実際のサイト自動生成では、静的ページやフォームの自動生成が難しい。情報表示用のテンプレート(サーバーサイドJSONView)は実は簡単。特に、(型→フォーム) という生成写像auto-formと呼ぶ。高階テンプレートの一番の用途はauto-formの実現である。

クォーティングによる高階テンプレートの実現

テンプレートテキストが単なるテキスト以上のものとなる根拠は、区切り記号とそれによるブロック構造である(http://d.hatena.ne.jp/m-hiyama/20070125/1169702291)。異なる区切り記号を持つ2つのテンプレート言語は、互いに他のメタテンプレート言語として使用できる。

もっと簡単な方法は、区切り記号のクォーティングまたはエスケープである。クォートされた区切り記号は、その評価が1回遅れる(何回でも遅らせることができるが)。この機能(クォーティングだけ)で高階テンプレート機能を実現できる。

例を示す。

次が実行時のテンプレート変数(コンテキスト)。

  1. title
  2. date
  3. content

生成時のテンプレート変数(メタコンテキスト)。

  1. siteTitle
  2. encoding
<?caty-meta template="smarty-mx" ?><<?caty-meta template="smarty-mx" ?>>
<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset={$encoding}' />
    <title>{$siteTitle} - {{$title}}</title>
  </head>
  <body>
    <h1>{$siteTitle}</h1>
     <h2>{{$title}} : {{$date}}</h2>
     {{$content|noescape}}
  </body>
</html>

展開を1回した後。

<?caty-meta template="smarty-mx" ?>
<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    <title>キマイラ飼育記 - {$title}</title>
  </head>
  <body>
    <h1>キマイラ飼育記</h1>
     <h2>{$title} : {$date}</h2>
     {$content|noescape}
  </body>
</html>

さらに展開。

<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    <title>キマイラ飼育記 - 最近思うこと</title>
  </head>
  <body>
    <h1>キマイラ飼育記</h1>
     <h2>最近思うこと : 2012-04-01</h2>
     <p>最近思うのだが ...</p>
  </body>
</html>