DT日記

家を離れた自宅警備員の日記

HTML+CSSの計算能力についての考察

ついったーで「HTMLでチューリング機械は作れるか?」といふ話題があったので考察。

チューリング機械と計算能力

チューリング機械 とは、イギリスの数学者 アラン・チューリング (Alan Mathison Turing) が計算可能性の定義のために提唱した想像上の装置。 ja.Wp の チューリングマシンチューリング完全チャーチ=チューリングのテーゼ あたりを参照のこと。

チューリング機械はそのシンプルな構造にも拘らず、割といろんな計算を実装することが可能で、2 + 3 みたいな単純な計算は云ふまでもなく、高度な条件判断を伴ふ複雑なプログラム(計算)を記述することもできる。このチューリング機械と同じ計算をすることができることを「チューリングマシンと等価の計算能力を持つ」「チューリング完全である」といふ。計算能力 とは計算時間や効率とはまったく関係がなく、 計算することができるか、できないか といふ問題。C言語Lisp, Ruby, JavaScript と言ったメジャーなプログラミング言語は、ほとんど漏れなくチューリング完全であると言ふことができる*1

単純には「無限長のテープを摸倣できるリスト(配列)」「条件分岐」「無限ループまたはリストに対する再帰的な操作」なんかができればチューリング完全と呼べさうですね。実用的なプログラミング言語なら、チューリング完全でないやうにする方が難しいよねー、って感じです。繰り返しますが、速度や効率はまったく別問題><

HTMLとCSSプログラミング言語か?

まづ、 HTMLCSS についておさらひ。HTMLマークアップ言語で、 CSSスタイルシート 。どっちもプログラミング言語じゃないです! はいをはり!

これでとは言っても、プログラミング言語ではないものに計算をさせてみるのもなかなか楽しいものなので、こんなことを考へてみまして。

2012-06-14 1st - jsdo.it - share JavaScript, HTML5 and CSS

何をやってるのかはソースコードを読んでもらへればばればれなんだけど、これで CSS にも計算能力があるぜやったー! ってことで良いのか……?

(- 5 5) とか Lisp っぽい記述がありますが、これは表示するのにわかりやすく書いてるだけなので、本質的には無視して良いものです。

<div class="add"><span class="n6">(+ 6 9)<span class="m9"></span></span></div>
<div class="add"><span class="n1">(+ 1 2)<span class="m2"></span></span></div>

肝腎なのは、これの div > span > span入れ子ですね。これ重要。

それじゃ、該当するセレクタのスタイル定義をば。

...
.add > .n6 > .m8:after { content: "14" }
.add > .n6 > .m9:after { content: "15" }
.add > .n6 > .m10:after { content: "16" }
...
.add > .n1 > .m0:after { content: "1" }
.add > .n1 > .m1:after { content: "2" }
.add > .n1 > .m2:after { content: "3" }
...

はい、すべての計算結果が定数で書いてありますね。しかもこのスタイルシートで対応してるのは 0〜20 までの二項の整数の四則演算のみ。いえーい。

hoge > fuga は、「hoge の直下にある fuga」 を意味します (セレクタ) 。 .foo は、 HTML の <span class="foo">< にマッチ。 piyo:aftercontent: "fugafuga" はセットで、 piyo にマッチした要素の内容の後に content で指定した 文字列が付け足される。

先の HTML コードは、本質的には次のやうな S式で表現することができる。

'(add 6 9) ; <div class="add"><span class="n6"><span class="m9"></span></span></div>
'(add 1 2) ; <div class="add"><span class="n1"><span class="m2"></span></span></div>

あるいはまとめてこんな感じ。

(define exprlist
  '(
    (add 6 9)
    (add 1 2)
    (sub 5 5)
    (sub 8 16)
    (mul 20 20)
    (mul 9 0)
    (div 3 0)
    (div 6 3)
    (div 100 10)
    (div -5 3)))

せっかくなので最近ちょっと勉強してる Scheme でこんなふうに書けると良いですね!

(define (html lst)
  (let ((v (assoc lst known-expr)))
    (if v v '(lst .  "undefined"))))

おまけに、こんな感じに既知の計算結果を定義しておきます。

(define known-expr
  '(
    ((add 6 9) . 13)
    ((add 1 2) . 3)
    ((sub 5 5) . 0)
    ((sub 8 16) . -8)
    ((mul 20 20) . 400)
    ((mul 9 0) . 0)
    ((div 3 0) . "NaN")
    ((div 6 3) . 2)))

この known-expr は上に引用した CSS のコードに相当します。

そいでもって、これで出力できると良いかな、って。

(for-each
 (lambda (x)
   (print (format "~a ; => ~a" x (cdr (html x)))))
 exprlist)

これを評価すると、こんな出力。

(add 6 9) ; => 13
(add 1 2) ; => 3
(sub 5 5) ; => 0
(sub 8 16) ; => -8
(mul 20 20) ; => 400
(mul 9 0) ; => 0
(div 3 0) ; => NaN
(div 6 3) ; => 2
(div 100 10) ; => undefined
(div -5 3) ; => undefined

はい、 HTML と CSS がこの一連の Scheme のプログラムとまったく同じ計算能力があることは證明できましたね!

それだけ?

うん。それだけ。

HTML をチューリング完全と呼ぶには何が足りないか

HTML は紙です。紙に計算を書き込むことはできますが、紙に計算能力はありません><

チューリングマシンでいへば、テープの役割をすることはできます。

CSSチューリング完全と呼ぶには何が足りないか

CSS はインクです。インクに計算能力は…と言ひたいところではあるのですが、実際には紙に書かれてる内容によって色が変ってねるねるねるね……もとい、程度の条件分岐をすることは可能です。

でも、再帰もできない、無限ループもできない。足りないものだらけ><

ではどうすればチューリング完全になるのか

HTML にも CSS にもそんなことは求めてません><

素直に JavaScript を使ってろと(ry

マークアップ言語やスタイルシートチューリング完全になれない?

んなこたぁーない

XSL の一部である XSLT (XSL Transformations) は、マークアップ言語 (XML 文書) でありながら、XML を変換するスタイルシート (変換言語) で、なほかつチューリング完全函数プログラミング言語でもあることが知られてゐます。

*1:無限長のテープ(メモリ)など存在しないので厳密にはチューリング機械と完全に等価ではないが、有限の記憶領域であってもチューリング完全として見做す