Upgrade to Pro — share decks privately, control downloads, hide ads and more …

XML 変換言語はチューリングおじさんの夢を見ない / Lambda calculus implementation by XSLT 1.0

XML 変換言語はチューリングおじさんの夢を見ない / Lambda calculus implementation by XSLT 1.0

XML データの変換言語である XSLT 1.0 を用いてλ計算の処理系を実装することにより、これがチューリング完全であることを示した。

東工大ロボット技術研究会 2018年度後期研究報告会 (2018-12-16) 発表資料。

speakerdeck だとスライド中のリンクが使えないので、 https://nextcloud.cardina1.red/s/Aae8AqRHnBs5RLn?path=%2Fpresentations にも上げてあります。

More Decks by らりお・ザ・何らかの天然水ソムリエ

Other Decks in Programming

Transcript

  1. だれ らりお • 情報工学系 M1 • CG-SQUARE • ゲーム完成したことなし •

    数年前から FBX 読んでる • 一応 3D 勢 • 静的型付き言語が好き • C++ わからん • Rust はいいぞ • 機械可読性信奉者 • XML 手書き勢 Contact: @[email protected] 1
  2. XML

  3. XML とは • Extensible Markup Language • HTML みたいなのをもう少し厳格にした汎用データ形 式

    (構文) • 木構造を表現できるので、カスタマイズして使う • 文書: XHTML, DocBook, TEI, … • ベクタ画像: SVG • 数式: MathML • その他諸々 (3D モデル、楽譜、 etc.) • 表のように綺麗に表現されないデータ (非構造化デー タ) を表現できる • json にかなり近い • 今は JSON でも昔は XML だったデータや API も多い 5
  4. XML の特徴 • 名前空間がある • 異なる意味と構造のデータを、シームレスに混ぜたり 埋め込める • たとえば「DocBook 文書中に

    SVG 画像と MathML の 数式を書き、 RDF でメタデータを書く」など • json はこれが苦手 • 一応 JSON-LD という規格はある • 構造とプリミティブデータを混ぜやすい • XML: <p id="po">Hello, <b>world</b>!</p> • json: [{"tag":"p","id":"po","content":["Hello, ",{"tag":"b","content":"world"},"!"]}] 6
  5. XML の処理 • 知らない語彙 (意味) を持つデータが入っていることが ある • SVG 画像を処理していたと思ったら、ラベルテキスト

    が MathML の数式だったり • 知らない語彙が来たら: • 無視する? • 知っている別の処理系に部分的に投げたい? • タグだけ無視してテキスト部分を抜き取る? • 自分にわかるように/欲しいように構造を修正したい • MathML の数式を LaTeX のソースにしたい? • MathML の数式をプレーンテキストにしたい? • MathML の数式を SVG 画像にしたい? 7
  6. XSLT • XSL: Extensible Stylesheet Language • XML を入力として受け取り、何らかの変換をして別の データを出力する

    • たとえば XML 出力 • たとえばテキスト出力 • たとえば LaTeX ソース出力 • パターンマッチと置換が基本 • 「このタグが来て、こういう特徴を持っていたら、こう いう構造に置換する」 • 「こういう場合は、子ノードにこういう置換をする」 • 再帰的な処理ができる (得意) 8
  7. XSLT コード例: HTML table 入力ファイル html-table.xml 抜粋 • HTML の表

    • 例 1: 最初の行と最初の 列をヘッダ (<th>) にし たい • 例 2: 表を CSV ファイル に書き出したい 9
  8. 計算とは? • 簡単な算術式は「計算」といえそう • 3 + 4 を 7 にするのは「計算」

    • 式を「計算」して数が出てくる • 最大公約数を求めるのは「計算」? • 算術式のみで書けないのでアルゴリズムで表現す るが…… • 一応、最大公約数を「計算」して数が出てくる • 導関数を求めるのは「計算」? • 微分は集合とか大小関係とかいろいろ使って定義する • 導関数を「計算」して、数ではなく関数が出て くる……? 14
  9. チャーチ=チューリングのテーゼ • 「計算可能な関数とは、帰納的関数である」という主張 • ある種の定義 • ここでは帰納的関数については説明しない • 情工民は授業で習う (習った)

    はず • いろいろな「計算」の書き方や「計算」の (形式的な) 方法が提唱されたが、だいたいどれも帰納的関数と同 じ強さ • λ 計算 • チューリングマシン 15
  10. チューリング完全な計算モデル • λ 計算 • 後で説明 • 数式を弄るっぽいお気持ちで計算が進む • 「すべては関数である」などと言われることも

    • チューリングマシン (チューリング機械) • 仮想的な計算機 (のしくみ) • 無限長のテープ (記憶媒体) と、それを読み書きする ヘッドからなる • 計算過程を物理的に想像しやすい • 他にもいろいろあるが割愛 • NAND のみによる論理回路とか 16
  11. チューリング完全 • チューリング機械で実行可能な計算をすべて表現でき る言語の特性 • λ 計算はチューリング完全 • C 言語はチューリング完全

    • チューリング完全な言語は、あらゆる「計算」を表現 できる • チューリングマシンで実行できるものが「計算」なの で、定義上そうなる • 「計算完備」とも 17
  12. オタクはすぐチューリング完全性を見出す • 何らかの「仕組み」は、油断するとすぐチューリング 完全になる • C++ のテンプレート • Rust の型システム

    • マジック・ザ・ギャザリング • HTML5 + CSS • SQL • マリオメーカー • ライフゲーム • その他諸々 • cf. 本の虫: うっかりチューリング完全になっちゃった もの 18
  13. チューリング完全だとなんなの • いいこと • どんな計算でも表現できる • (書きやすいとは言ってない) • わるいこと •

    停止性が有限時間で確実には判定できない • 止まるとは限らないし、止まらないとも限らない • 実行してみないとわからない (実行してもありうる全て の入力についてはわからない) • →停止性問題 • 不必要に複雑になっている場合が多い • 文書データで「何でも計算できる」? • 型推論で「何でも計算できる」? • 設定ファイルで「何でも計算できる」? • 設定ファイルの読み込みに停止性がない……? 19
  14. で? • 本題: 「 XSLT がチューリング完全っぽい気がしたので、 XSLT 1.0 で λ

    計算の処理系を実装した」 • つまり: • XSLT が: XML データ加工言語が • チューリング完全: どんな計算でも書ける • っぽい気がしたので、 • XSLT 1.0 で: XML データ加工言語で • λ 計算の: どんな計算でも書ける別の言語の • 処理系: 処理 (今回は実行) を行うプログラム • を実装した 20
  15. 帰着 • ある問題 A を、別の問題 B に帰着 (還元) • 「B

    が解けるなら A も解ける」と示す • B を解く方法を、 A を解く過程で用いる • この場合、 「A は B 以上に簡単である」と言える • λ 項の評価 (計算) を、 XSLT による XML 変換に帰着 • 「XSLT で XML を変換できるなら λ 計算も計算できる」 と示す • XSLT による XML を、λ 項を評価する過程で使う • この場合、 「λ 計算は XSLT による XML 変換以上に簡単 である」と言える • → XSLT には、チューリング完全な言語以上の計算表現 力がある • → XSLT もチューリング完全 21
  16. λ 計算 • チューリング完全な言語のひとつ • 項書き換え系 • 数式のように、項の書き換えによって計算が進行 • 「命令」や「手順」でなく「結果になるもの」が表現さ

    れている • 雑に言うと: • 「変数」と「λ 抽象」(関数っぽいの) がある • 関数適用ができる • おしまい • 変数の書き換えなんてものはない 22
  17. 項書き換え系: Term Rewriting System • 規則に従って、与えられた式を書き換える • 典型的には、数式 • (3

    + 2) × (1 + 1) → 5 × (1 + 1) → 5 × 2 → 10 • λ 計算も • (λa. (λb. (λc. (a c) (b c)))) (λx. (λy. x)) → (λb. (λc. ((λx. (λy. x)) c) (b c))) → (λb. (λc. (λy. c) (b c))) → (λb. (λc. c)) • 書き換え規則は帰納的 (再帰的) に与えられることが 多い • 各規則の適用条件の判定にパターンマッチを使うこと も多い • 構造的帰納法みたいな 23
  18. de Bruijn index • (発音的に) 読めないことに定評あり • 変数 (引数) を名前で参照せず、相対位置で参照する

    • 名前だと被る • 位置だと被らない • 「いくつ上の λ で導入された引数か」 • 0 で始める派閥と 1 で始める派閥が… (#0 は自然数) • Wikipedia が 1-based だったので 1 からで実装しました de Bruijn index: Wikipedia より 24
  19. 構成: データ • データは 3 種類 • XML による通常の λ

    項の表現 • 普段利用する入力。糖衣構文あり • XML による de Bruijn 項の表現 • 評価に使われる形式。入力としても利用可能 • プレーンテキストによる de Bruijn 項の表現 • 出力専用 • XSLT スタイルシートは、 XML データを受け取り、 XML またはテキストを返す 26
  20. 構成: パイプライン (1) • desugar • 糖衣構文を剥がす • 入出力ともに λ

    項 • conv-to-de-bruijn-term • λ 項を de Bruijn 項に変換する • 入力は糖衣構文なしの λ 項、出力は de Bruijn 項 • onestep-reduction • de Bruijn 項を最左最外簡約で 1 ステップ評価 (β 簡約) する • 入出力ともに de Bruijn 項 • eta-reduction • de Bruijn 項を可能な限り η 変換する • 入出力ともに de Bruijn 項 27
  21. 構成: パイプライン (2) • reduction-steps • de Bruijn 項について eta-reduction

    (η 簡約) と onestep-reduction (β 簡約) の処理を可能な限り繰り返 し、その過程をリストで返す • 入力は de Bruijn 項、出力は de Bruijn 項の配列 • full-reduction • de Bruijn 項について eta-reduction (η 簡約) と onestep-reduction (β 簡約) の処理を可能な限り繰り返 し、その結果の式を返す • reduction-steps が返すリストの最後の項目を返すのと 同じ • 入出力ともに de Bruijn 項 28
  22. 構成: パイプライン (3) • pretty-print • λ 項または de Bruijn

    項について、そのテキスト表現を 返す • 入力は λ 項または de Bruijn 項、出力は λ 項または de Bruijn 項のテキスト表現 29
  23. 詳細: desugar • 脱糖: desugar.xml • 3 つの変換を、順に適用 • let-expr:

    let 式から λ 抽象へ • let a=b in c を (λa. c) b に • let* a=b, c=d in e を (λa c. e) b d に • apply-at-once: 関数適用を 2 項単位へ • (a b c) を ((a b) c) に • (a) を a に • multiple-params: λ 抽象をカリー化 • (λa b. c) を (λa. (λb. c)) に • 抽象構文木の書き換えなので、 XSLT と非常に相性が 良い • 更に他の拡張を足すことも容易 30
  24. 詳細: conv-to-de-bruijn-term • λ 項を de Bruijn 項に変換: conv-to-de-bruijn-term.xsl •

    変換において、名前のリスト (環境) をテンプレートの 引数として持ち回る • XML の木構造を使う方法と文字列による方法がある • 今回は文字列を利用 • 与えられた項とその部分項について、環境を加工しつ つ再帰的に変換 • 引数として宣言された変数を、環境に追加 • 注目している変数を環境から探し、順番を返す • <var>x</var> などを <de-bruijn-var index="1" /> などに 31
  25. 詳細: onestep-reduction (1) • 1 ステップ β 簡約: onestep-reduction.xsl •

    最左最外簡約 (leftmost-outermost reduction) • 停止しうる計算が必ず停止する評価戦略 • 最も外側、最も左側にあるものから簡約基を探し、ひ とつ選んで簡約 • 簡約場所のチェックと実際の簡約で、ツリーを 2 回走査 • 書き換え可能な変数で「既に何かを簡約したか」を記 憶しておけないため • 最初に、左右の項が値であるか (これ以上の簡約が可能 か) を確認 • 2 回目で、簡約を実行 32
  26. 詳細: onestep-reduction (2) • 注目している項について簡約を実行: • 自身が変数なら放置 • 自身が lambda

    なら、本体を再帰的に簡約 • 自身が apply なら、左の項が値であるか、また λ 抽象 であるか確認 • λ 抽象なら、代入により適用の項を簡約 • λ 抽象でも値でもないなら、左の項を再帰的に確認 • λ 抽象でなく値なら、右の項を再帰的に確認 33
  27. 詳細: eta-reduction • η 変換: eta-reduction.xsl • 内部的に実装した 1 ステップ

    η 変換 (int:eta-reduction-step) を、結果が変化しなく なるまで繰り返す • 結果の変化確認: pretty-print して文字列比較 • XML の木構造そのものを比較するのは (XSLT では) 基 本的に厳しい • ノード (或いはその集合) 同士の比較は、テキストだけ 抽出した文字列についての比較になる • cf. XPath 1.0 spec, §3.4 • 1 ステップ変換は次スライドで解説 • 雑に繰り返しても必ず止まる • 項サイズが大きくならない変換だから 34
  28. 詳細: eta-reduction-step • (λ t $1) の形の式で、かつ t 部分で $1

    が使われて いなければ、これを t に変換する • λ 抽象で: template match="de-bruijn-lambda" • その λ 抽象の本体が関数適用で: apply • その関数適用の最後の項が: *[last()] • de Bruijn 項の変数で: [self::de-bruijn-var] • その変数が $1 である: [@index=1] • かつ、 • 関数部で: apply/*[position() != last()] • $1 が使われていない: apply-templates mode="int:find-de-bruijn-index-used" 35
  29. 詳細: reduction-steps, full-reduction • 評価過程を返す: reduction-steps.xsl • η 変換 (任意)

    と β 簡約 (必須) の 1 ステップ評価を、結 果が変化しなくなるまで繰り返し実行 • 途中経過も含めて、評価過程の式のリストを返す • 全ての redex を簡約して評価結果を返す: full-reduction.xsl • reduction-steps の最後の式 (リストの最後) だけを返す 36
  30. やるだけ? • λ 式の評価と XSLT による変換はよく似ている • 部分項 (部分木) に対する再帰的な処理

    • 処理結果が入力 (処理前データ) を置き換える • 項の構造によって処理が変化 (パターンマッチ) • λ 式に対する処理を素朴に翻訳すると、対応する XSLT コードが書ける 38
  31. 比較例: de Bruijn 項 の 1 ステップ評価 (1) • (λ.

    t12 )v2 → ↑−1 ([1 →↑1 (v2 )]t12 ) • XSLT の場合は: • (λ. t12 )v2 : • もし関数適用で (template match="apply") • 最初の子 *[1] が λ 抽象の de Bruijn 表現である [self::de-bruijn-lambda] なら • ↑−1 (·) • -1 シフト (with-param name="shift" select="-1") を • 適用 (call-template name="int:shift") する 39
  32. 比較例: de Bruijn 項 の 1 ステップ評価 (1) • (λ.

    t12 )v2 → ↑−1 ([1 →↑1 (v2 )]t12 ) • [1 → ·]t12 (-1 シフトの中身) • t12 (de-bruijn-lambda[1]/*) に • 変数 1 への代入 [1 → ·] (with-param name="lhs" selet="1") を • 適用 (apply-templates mode="int:substitute") する • ↑1 (v2 ) (変数 1 に代入する項) • v2 (*[2]) に • 1 シフト (with-param name="shift" select="1") を • 適用 (apply-templates mode="int:shift") する 40
  33. 比較例: de Bruijn 項 の 1 ステップ評価 (3) • 評価規則と

    XSLT のデータ構造がかなり近い • ほとんど規則を XML で書くだけの作業 • →やるだけ 41
  34. 実行例 • テストケース (特に reduction-steps) 参照 • 05-eta-identity-1, 06-eta-identity-2, 08-eta-identity-3

    • η 変換 • λx. (λy. (λz. z) y) x や λx y z. x y z 等 • 09-ski-one-plus-two, 10-three-plus-four • SKI コンビネータと Church 数で 3+4 を計算 • let 式と let* 式の脱糖のテストでもある • let* S=(λx y z. x z (y z)), K=(λx y. x), I=(λx. x), B=(S (K S) K), succ=(S B), add=(S I (K succ)), two=(succ I), three=(succ two), four=(two two) in add three four など 42
  35. XSLT の機能と EXSLT 拡張 • 実は XSLT 1.0 の標準関数に加えて exsl:node-set()

    も必要 • だいたいどの処理系も実装してるのでおk (ほんまか) • XSLT 1.0 では「テンプレートで生成されたノードについ ての再度のパターンマッチ」が不可 • 入力文書の部分木に対してしかパターンマッチでき ない • 素の XSLT 1.0 だと木を再帰的処理できない • node-set() はこれを無理矢理可能にする拡張 • XSLT 2.0 以降だとこの拡張は不要 43
  36. 先行研究・実装 (1) • Universal Turing Machine in XSLT - Unidex

    • XSLT 1.0 による万能チューリング機械 • 万能チューリング機械: 「コード化されたチューリング 機械を入力として、これを実行するチューリング機械」 • 一種のエミュレータ • オタクは再帰がすき • チューリング機械 (遷移関数と状態) を XML で表現 • テープ状態は文字列で保持 • ノードだと再帰できないので、文字列で持つしかな かったものと推察 • 文字列操作だらけ • 正直 XSLT である必要はない • チューリング機械の状態をテンプレート関数へのパラ メータとして持ち回り、再帰でループする 44
  37. 先行研究・実装 (2) • XSLT Version 2.0 is Turing-Complete: A Purely

    Transformation Based Proof • XSLT 2.0 におるチューリング機械の実装と証明 (?) • チューリング機械 (遷移関数と状態) とテープ状態を XML で表現 • exsl:node-set() 相当の機能を利用して再帰 • XSLT 2.0 ではテンプレート出力を入力として再利用で きる 45
  38. 先行研究・実装 (3) • A proof of the Turing-completeness of XSLT

    and XQuery • A Simple Proof for the Turing-Completeness of XSLT and XQuery. • XSLT 1.0 と XQuery それぞれで μ 再帰関数を実装する方 法を提示 (帰着) • μ 再帰関数: 自然数から自然数への部分関数の集合 • チューリングマシンで計算可能な関数と一致する • → μ 再帰関数が実装できる言語はチューリング完全 • スタック構造を文字列演算で実装 • コールスタックや計算結果の一時退避に使う • XSLT 1.0 版は非常に手続き型言語的に動作する (気が する) 46
  39. 先行研究・実装 (4) • The interpreter of the Lambda-calculation ( XSLT

    ) • 発表日前日に探したら見付かった • 2001 年 11 月 • 新規性を奪われた、草生える • λ 項を XML で表現する • 私がやったのとほとんど同じ • node-set 拡張を利用 • 評価は 1 ステップごとでなく、やれるだけまとめてやる • モジュール化は激しくない • α 変換 も de Bruijn 項への変換もしていないので、バ グがある • たとえば (λ x.(λ y.y(λ x.x)))(λ y.y) • (λ y.y(λ x.x)) になるべきだが、 (λ y.y) が出力される 47
  40. 優位性 • 新規性なんてなかった • 何年前のことでもちゃんと調べような • チューリング機械や μ 再帰関数への帰着に比べて: •

    素朴かつ単純 • 評価規則がほぼそのまま XSLT 記述になる • 実用性が高い (個人の感想) • 既存の λ 計算処理系に比べて: • 実装が正しい • 変数名の衝突に耐性がある • モジュール化が進んでいる • 糖衣構文や機能拡張が容易 • 部分的な機能利用が容易 • デバッグが容易 48
  41. まとめ (1) • XSLT 1.0 のチューリング完全性を PoC で示した • λ

    計算への帰着による • 厳密な証明ではない • データの流れが評価規則の定義そのものと極めて類似 しているため、証明は容易のはず • 読者への宿題とする (適当) • チューリング機械に帰着せず、λ 式の抽象構文木を素朴 に処理した • 実用性、拡張性も高い • 文字列処理はお呼びでない • チューリング完全性についての直観を補強した • 「パターンマッチと置換と再帰があれば基本的に チューリング完全っぽい」 49