Today アクセスカウンター Yesterday アクセスカウンター

ホワット・ア・ワンダフル・ワールド

私は知識に何ものかを付け加え,また他の人々がより多くのものを付け加える手助けをした --- G.H.ハーディ

全記事一覧 << 2008/07 12345678910111213141516171819202122232425262728293031 2008/09 >>

プロフィール

あろは (alohakun)

  • Author:あろは (alohakun)
  • 若槻俊宏 (WAKATSUKI toshihiro)

    連絡先 : alohakun ___at___ gmail.com
    mixi : http://mixi.jp/show_friend.pl?id=182927
    twitter : http://twitter.com/alohakun

    abstract

    プログラミングという人間の知的行為を体系化し,単なる職人芸ではなく,サイエンスにするための研究をしています.

    具体的には,等価変換計算モデルに基づいた,仕様記述からのプログラム合成の研究をしています.

    もっと噛み砕くと,プログラムの正しさをどのように定式化し,どのような枠組みで,どのように変換を進めていけば,正しさを保証したまま,効率的なプログラムを手に入れることができるのか,ということについて研究しています.

    キーワード : equivalent transformation, computation model, programming paradigm, formal specification, program synthesis













    あわせて読みたい


    この日記のはてなブックマーク数


    スカウター : ホワット・ア・ワンダフル・ワールド


    Map









    FC2 BLOG RANKING

FC2カウンター

ブロとも申請フォーム

この人とブロともになる

プログラミング言語の速度

2006/12/02(土) 02:30:50

コメント欄に書いてたら,長くなってしまったのでこっちに加筆して転載.

soutaroにっき ■プログラミング言語の実行速度 00:23

大体俺の中では,

C>C++>OCaml(native)>Java・.NET>Haskell>>>VB6>OCaml(bytecode)>Perl/Python>>>>Ruby

みたいなイメージ.合ってるかどうか全然自信ありませんのでバカ日本地図を眺めるような感じで見てください.

つまり,Javaより速いって聞くと「速っ!!」っていうイメージになるんですよね.

んで,Java・.NET以上なら,大体どんなアプリケーションでもいけると思うんですが,そうするとOCaml(native)の立場が微妙になる感じがする.それにRubyでもがんばればけっこうなんとかなるみたいですし,そうすると結局プログラミング言語における実行速度というのはいまやほとんどのケースで問題にならないのかもしれないと思ったり思わなかったり.

そもそも,CとRubyでもせいぜい数十倍程度のオーダーしか違わないことがほとんどのような気がするので,なんかこういうのを比較するのは不毛かなぁとも思いますし.


僕の中では,C/C++ が速いのは,ある程度限定されたクラスのアプリケーションに限定されるんじゃないかと思います.パタヘネ (僕が読んだのは第二版だけど) の中で出てくる,「確かに人間がハンドコードしたアセンブリコードは限定された部分だけに限れば速いけど,平均的には高級言語が生成するコードの方が良質.そもそもコンパイラの生産性に勝てる人間はいないし,規模がある程度になれば全てをハンドコードするのは現実的には不可能」 みたいなのと同じ意味で.

# ベンチマーク程度の玩具プログラムなら,機械に近い言語が速いに決まってる,という.あるいは,Haskell のたらいまわし関数とか.

たぶん,OCaml や Common Lisp が対象とするような規模のアプリを,C/C++ で真面目に書こうとすると,最初に本質とは無関係な大がかりな足場 (抽象化のためのしくみ) が必要になって,そのせいで全体的なオーバヘッドがでかくなる気がします (普通のプログラマの場合ね.もちろん,超人はどんな世界にもいるんだろうけど).

# グリーンスパンの第10法則 「十分に複雑なCまたはFortranのプログラムは全て、後付けで、正式な仕様がなく、バグがてんこもりの、遅い、CommonLispの半分の実装を含んでいる」

結局,作り込めば作り込む程,速く,良質なコードになるのはあたりまえなので,現代では実行速度云々よりも,開発速度の方がはるかに重要な要素になってると思いますね.C/C++ とか使ってると,ついつい面倒でアルゴリズムを手抜きしたくなるとか (つまり,俺のことなんだけど).アルゴリズムがアホ過ぎると,定数倍の速度差なんて全く誤差になる.

とはいえ,数十倍程度,という感覚がモダンで素敵ですね :-)

個人的には,2 倍でも全然違うと思いますが…

0.1 秒が 6 秒,1 秒が 1 分とかならともかく,1 時間が 60 時間,一日が 2 ヵ月みたいに,アプリがでかくなればなるほど,定数倍とはいえ,シャレにならなくなってきますよ w

スパコンと FORTRAN の世界では,数ヵ月シミュレーションプログラムを回しっぱなしなんてのもざらですし (精度をちょっと上げると,あっというまに計算量が爆発するから,いくら速くても全然足りない.あればあるだけ使う世界).3 ヵ月が 180 ヵ月になったら… 計算機がいくら速くなっても,いや高速大容量になればなるほど,扱うデータの規模も比例してでかくなるのが道理.

# この理由一点により,FORTRAN は永遠に不滅だと思う.というか,FORTRAN コンパイラの枯れ具合は物凄いらしい.C/C++ コンパイラなんて (まぁ,言語仕様の柔軟性の差がでかいんですが.ポインタが無いとか) 全く相手にもならないという世界もあるのです.

ジャーネスッポスッポ先生が偉大なのは,ここらへんをちゃんとわかってるからだと思います.どれだけ素晴らしい言語でも,速度の問題一つで,現実的には全く使いものにならない世界がある.すっぽすっぽ先生は Simula が大好きだった… でも使いものにならなかった.こんなトロトロのプログラムじゃ,いつまでたっても学位は取れない.そして決意した.本物の,実用的なオブジェクト指向言語を作ろうと (プロジェクト X).

Technology ReviewによるBjarne Stroustrupインタビュー

TR: 最も後悔することは何ですか?

BS: 後悔はありません! もちろんもっと違った形でうまくやれたかもしれないと思うことはありますが、真面目に言って、私が1984年のBjarneにけちをつけられるでしょうか? 彼は今の私より経験は少ないですが、より無能であったというわけではなく、おそらく今よりも賢く、1984年について私よりもよく理解していたでしょう。 C++は我々の生活を向上させる多くのシステムを構築するために使われており、後発の言語やシステムに重要な良い影響を与えました。これは誇るべきことです。

教授はいつもカッコ良すぎる…

まぁ,単に私が GA とか NN とか,AI 系に特有の,馬鹿みたいに大量の単純データでひたすら計算機を 3 日 3 晩ぶん回し続けるような世界に馴れ親しんでいるだけかもしれませんが (^-^;

なんとなく,Ruby の人 = Web 系の人という感じで,Web の人達はそれが世界の全てだと思ってるふしがあるような… そういえば,松本さんが COBOL をどうこう言って,最近一波乱あったみたいだし.

# 僕も COBOL は全く知りませんが.

逆に言うと,よく Lisp の人が,ボトムアッププログラミングがどうこう言うけど,はっきり言って,マクロ程度のプログラム変換と,本物の Prolog コンパイラを一緒にしたら失礼なような…

同様に,Prolog や CHR みたいな制約 (論理) 型言語が対象とするような抽象度のクラスの問題を解く際には,関数型言語も先の例と同じ意味でオーバヘッドが大きくなってくると思う.

いくら Lisp で Prolog が書けると言っても,それはあんまり意味が無いと言うか.Lisp には Lisp の,Prolog には Prolog のレベルの最適化があって,それは全然違うものだし,最適化は大域的なものであればあるほど効果的なので.単一化器とか制約ソルバーの最適化一つ取っても,Lisp 言語のオブジェクトレベルから見ている限り,極めて限られたローカルな最適化しかできないと思う (いや,もちろん Lisp で Prolog コンパイラを書ける,とかいう話とは,また別ですよ.その理屈で言ったら,何でも書けるアセンブラが最強になってしまう).

結局,プログラミング言語にとって一番重要なものは,数学的な裏付けでも,読み書きのしやすさでも,速度でも,もちろんマクロでも無い.極端なことを言えば,言語はどうでも良い,というのが私の立場.

いかにして仕様を記述し,いかにしてそれを効率的に実行可能な形にまで等価変換していくか.これこそがプログラミングの本質だと,私は思う.そしてその過程においては,様々なレベルの様々な知識が要求される.

そもそもコンパイラという言葉が良くない.言語処理系は,死ぬ程雑多なバッドノウハウに満ちた計算機上で効率的に動くプログラムを仕様から生成するための,エキスパートシステムにならないといけない.

今の計算機科学ってのは根本からどうしようもなく間違ってる.理論屋は泥臭い現実は見ないし (結局インプリ頼み.理論は建前),現場は宗教とまじないが渦巻く原始的な世界になってる.いくら理論的には綺麗でも,計算機の上で動かす以上,かならず汚い部分は生まれて,それは結局コンパイラという黒魔術の中に全て隠蔽されてしまう.そして,現場の納期と戦う人間には,何冊も何冊も何冊も何冊も専門書や論文を読むような時間なんて絶対無い.

そうすると,いざ抽象化が漏れた時には,普通のプログラマにはどうしようもなくなる.結局知識とスキルのある人間が一からブラックボックスを検証しないといけない.こんなのは最高に馬鹿げてる.

エキスパートほげほげげとかナントカ depth とか,何冊も何冊も瑣末な言語のバッドノウハウについて自然言語で本を書く暇があったら,それを知識ベースとしてエキスパートシステムに登録しておけば良いのに,と思う.CPU ベンダとかも,人間に向けて読みにくいマニュアルを書く暇があったら,全部機械が理解できる形のデータにしておけば良いのにと思う.

こういうのは,現在の価値観からすると夢物語,ばかげた空想に聞こえるかもしれないけどね.人間が瑣末な知識を大量に覚える代わりに,機械にその知識を登録するのは確かに大変だけど,人間の教育のコストに比べたらはるかにコストが下がるし確実だ.人間が手で経験則で最適化する代わりに,機械に定量的なプロファイルを取らせながら最適化をさせる.

これは,本物の AI の実現なんかに比べたら,はるかにはるかに現実的だと思うのにねぇ.少なくとも,セマンティックウェブよりも w

数学は確かに素晴らしいものだけど,それが表現できるのは極限まで抽象化され,細部がそげ落とされた現実のほんの一部.物理学みたいな抽象的な学問ならともかく,計算機なんていう気まぐれな歴史や部品の値段相場アレコレもろもろが絡み合う雑多な現実を扱うには,あまりにも非力だと思う.計算機には計算機の 「知識」 を正しく扱う体系が必要だと思うのよねん.

もちろん,5 年や 10 年のスパンの話じゃないですよ.計算機科学が,真に一歩前進するための僕なりのビッグビジョンというか.50 年 100 年後の計算機科学はどこに向かえば良いのか,という話.

なんかエライ脱線した.やっぱり眠い時に文章書くと駄目だな.
研究TB:1CM:14 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

パターンからのプログラム生成

2006/07/18(火) 12:26:07

私は常日頃から,仕様記述 (What) とプログラム記述 (How) は分離するべき,と言っているのですが,やはりこれはいろいろと誤解を招くようです.

UML みたいなレイヤーも,仕様記述と言えば仕様記述ですが,ちょっと曖昧すぎますよね.あれはどちらかというと,非常に荒いスケッチ,ラフデッサンです.

むしろ,パターン言語 (あるいは言語から独立した DSL,特定問題領域に特化した仕様記述言語) からの,実行できるプログラムの自動生成と言った方が,正確なイメージが伝わるのかなぁ,とか思いました.

日々の破片 : プログラマーのためのデザインパターン


パターン言語とは、設計過程で発生するあらゆる問題に対し、実際に機能するソリューションを提供することで、設計者を導くというものだ。パターン言語は、一連のちょっとした知識がある一定のスタイルで記述、整列されており、設計者がその時点で最も適した質問を尋ねる(または答える)ことができるようになっている。

(良く考え抜かれたFAQとはパターン言語のインスタンスか?)

パターン言語を、これから生まれるものを記述するために利用するのではなく、すでに存在するものを記述するために利用する。そのような利用方法が効果的かどうかを試す。

(via ja.reddit.com)

例えば Ruby なり,Haskell なりでのプログラミングが非常に快適だ,と感じる人は,その言語の中に埋めこまれたパターンに沿ってプログラミングを行うのに向いている問題領域を相手にしているからなのでしょう (これを,パラダイム,とか言ったりもします).

# オブジェクトというモジュールの組合せでプログラミングとか,関数というモジュールの張り合わせで高階プログラミングとか,map-filter-accumulator でパイプライン処理とか.

んで,なぜ特定のパラダイムなり言語が優れているかと言うと,既にある程度確立された問題ならば,ほとんど何も考えなくても,言語なりフレームワークなりライブラリなりに沿って書いて行くだけで,問題が解決できてしまうからなのですよね.

そして,プログラマの仕事のほとんどは,それで事足りてしまうのもまた事実なのでしょう.

(これは,あるいは逆で,プログラミングの水準自体が低いから,高度な要求自体が出て来ない (発想できない) のかもしれません.鶏卵ですが)

しかし,現在のプログラミングの水準は全然足りてない,と常に感じている問題領域があります.

AI です.

Lisp (記号処理的 AI) も Prolog (自然言語処理) も ML (定理証明) も,真に新しい言語のほぼ全ては,実務ではなく,AI 分野の要求から生まれて来ました.

人工知能の第一人者J・マッカーシー氏に聞く -- AI研究、半世紀の歴史を振り返る

スキルという問題ではなく、ハードウェアを活かすための基本的なアイデアがなかったということです。その点は今でも変わっていません。そのことは、コンピュータにチェスと囲碁を同じくらい学習をさせると、チェスはかなり巧くなるけれど、囲碁は全然巧くならないという事実によく現れています。囲碁では、局面、陣地を考慮しなければなりませんし、何より、囲碁の"手"を識別する必要があります。こうしたことは、コンピュータ上でどのように表現すればよいのか未だに分かっていないのです。


こういう分野では,既にあるパターンにそって,少ないコストでプログラムが書けるというだけでは不十分なのです.

それゆえ,逆に,特定のパラダイムに染まった言語は,AI 研究には向かないということになってきます (パラダイム,フレームワークが檻,思考の制約,足枷になってしまう).

特定の問題解決を行うためのパターンを蓄積していくことは重要ですが,従来の言語設計のように,トップダウン式になんらかの型に言語をはめてしまってはいけないのです.

ここらへんのジレンマを解消するためには,実行環境としてのプログラミング言語と処理系 (計算システム) と,仕様 (パターン) を記述し,それから実行環境で走らせることができるコードを生成するしくみ (メタ計算システム) の分離が必要不可欠だと,このシュトロハイムは思いますよ.

# 何度も言いますが,UML だけが仕様記述ではないのです・・・ しかも,むしろあれは,OOP というパターンを記述するためのパターンという,二重の意味で狭い手法です.だから,最初から OOPL でコード (OOP を記述するためのパターン言語) を書いた方が早い,となる.

こういう動きは,(不完全ながらも) いろいろな所で生まれつつあるように感じます.

たとえば,Java という OOP の 「仕様記述」 から,JavaScript という 実行のための 「プログラム記述」 を生成するという,Google のコンパイラ.

JavaScriptの未来(非ネタ編、ラップバージョン)

従来の高級言語は,アセンブリ言語を実行用言語として生成していましたが,これからは仕様がより高級な言語の代わりとなり,従来の高級言語を実行用言語として生成するようになる,と.

# 今でも,生成されたアセンブリ言語を直接眺めたり編集したりする人はけっこういますよね.GCC で一番使うオプションは -S です ! みたいな w

# 今後は,C とか Java とか JavaScript とかが,同じような感じで,人間が最初から手書きする物では無くなって行くと思います.

もちろん,C with Classes がうまく行かず,結局 C++ を必要とした (そして,OOP その他もろもろの仕様記述と実行記述が分離してないがゆえに,どちらも中途半端になってしまった) ように,実行記述用の言語は,どんな言語でも良い,というわけではありません.

(実行言語自体を高級化しようとすると,処理系の移植性とか効率とか,いろいろなものが犠牲になります.また,処理系の都合に言語使用が引っ張られるので,仕様記述能力も低下してしまいます.これが,どっちも中途半端になる,ということ)

できるだけ,癖が無く,ニュートラルな言語.

(というのだけならば簡単ですが,非常に難しい.言語設計者は,ついつい,自分が良く知っている問題領域を意識して,それを記述しやすいように言語を設計してしまいがち.様々な DSL から自然に落すことができるニュートラルな言語,そしてそれは通常,人間が読み書きするものではない,という根本的なパラダイムシフトが必要だと思います)

(それがどんなものになるかは,私は正直よくわかりません.とりあえずは,やっぱり S 式なのかなぁ・・・ という気はしますが.ET もふつうは R 式 (if-then のエキスパートシステム (プロダクションシステム) 的ルール) で書いて,メタプログラミングの時は S 式で扱うというやり方を (まだ不完全ならがらも) とっています.仕様記述,ルール生成,ルールの実行コードへのコンパイル,までの一連の流れを作るというのが,ET パラダイムの (現実的な方の) 目標.もっと大きな目標もあるのですが)

ここから (いや,この blog 全てですが w) はヨタ話ですが,人工知能の逆説的なテーゼで,「知能 (知的ふるまい) とは,人間にできて機械にはできないことだ」 というのがあります w

(つまり,人工知能は,知能の定義からして本質的に不可能 w)
(一番難しいのは,何をもって知能とするか,そもそも人間は本当に知的なのか ? とか,そういうところなのかもしれません.不毛な言葉遊びですが)

昔は高度な技能とされてきたことでも,一度機械化されると,知的とは見なされなくなっていくのですね.

だから,AI は自分とは無関係だ,と思うのは,ちょっと違うのです.今の最先端の AI 研究が,おそらく 50 年くらいすると,当たり前の手法なり言語となって,普通に業務で使われるようになっていくのです,たぶん.

まぁ,もしかしたらその時には,プログラミング (コーディング) 自体が,もはや知的とは見なされなくなっているかもしれませんね.
研究TB:0CM:2 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

要素技術にかまけすぎて目的を見失いそうだ

2006/07/14(金) 12:18:54

卒論あたりで散々言ってきた考えてきたことなんですが,もう一度整理.正直辟易していますが,最近要素技術が楽しすぎて,研究本体を全くやってなかったので,目的を見失いつつあります.

# ただ,いままで若干感じていた,ボスとの間の方向性の相違は解消されたのが救い.目指しているものはいっしょ (とりあえず,仕様から機械語までの道筋を作る,各ステップのブラッシュアップはその後,あまり要素技術を早すぎる最適化しても無意味,ある程度の道筋さえ作れば,あとは勝手にパラダイム自体が進化していくはず) だったのですが,表現のしかたが違っただけ.コミュニケーション重要.ボスも私も,けっこうテキトーなので,お互いそのときの気分で発言の内容がコロコロ変わるからなぁ w (チラシの裏)

関数型言語ってのは,数学という仕様記述手法にプログラミング言語を近づけたいんですよね.

数学にもいろいろありますが,主に形式的な構文中心のところ.

構文中心ということは,字面を見るだけで何もかもわからないといけない.裏でこっそりメモリなどの状態が変化してしまうと,字面だけでは見通すことができないから,言語をなるべくピュアに,副作用をなるべく排除しようという思想に自然と至ります.

副作用を排除,ってのが,まぁ,根本的に間違っているような気もするわけですが,これは一理ある考え方です.

副作用が無ければ,やっかいな多重処理関係のハイゼンバグやら何やらが,100 % 無くなります.非常に簡単に並列処理やら何やらができ,プログラムの静的検証も容易になるなど,良いこと尽くめです.

ただ,副作用を排除しようとすると,どうしても効率は犠牲になります.メモリを上書きして再利用することもできなくなるので,GC やら何やらを使用し,無限のメモリをエミュレートすることが必須になります.

それじゃ困るよね,ということで,遅延評価やらプログラム変換やらのオプティマイズ技術が発達することとなりました.

# ここらへんニワトリと卵ですが.解析技術が無いと使い物にならない,ある種無理矢理な体系だから発達したのか,純粋関数が,解析技術を構築しやすい優れた体系だったから解析技術が発達したのか.

遅延評価で,不要なコピーやオブジェクトの生成をなるべく減らし,プログラム変換で,潰しても問題無いメモリや正格に評価しても良い部分を判別し,自動的に副作用や先読み評価を,理論的に安全な範囲で活用する早いプログラムに作り変える.人間の手が入らないので,バグが入る恐れもありません.

今までの手続き型言語の世界からすれば,どれもこれも目から鱗でしょう.関数型マンセーの人が急増するのも無理は無いです.

手続きの人から見れば,オブジェクト指向は檻からの解放だったみたいに (関数の人から見れば,オブジェクト指向は関数のほんのサブセットの牢獄ですが).

ただ,関数型言語ってのは,根本的に低水準なんですよね,少なくとも,ある種の制約解消型の言語からすれば.

ぶっちゃけ,全ての関数型言語は,つるかめ算すら解くことはできません.

■宣言的プログラミング?

よく「命令型言語は手順を記述し、関数型言語は問題を記述する」と言いますが*1僕は嘘だと思います。たとえばつるかめ算の問題をHaskellで(ましてやMLやSchemeで)記述しても解けないわけで。論理型言語も(程度の問題はあれ)同様かと。

*1:ちゃんとした人が言っているのかどうかわかりませんが
(住井先生の日記 - ■宣言的プログラミング?)

# 今,LL とか言って,猫も杓子もトリビアルなトイ問題を各々の言語で解いて騒いでますが,例えば制約ソルバーを備えた論理型 (制約論理型言語とか呼ばれます.制約プログラミングというプログラミングパラダイムの一実装手法で,かならずしもこれだけが全てというわけではありません) や,ユーザ定義制約を許し,マルチヘッドルールを採用し,より柔軟で大きな制約解消を実現した (ET のサブセットである) CHR などでは,そこらへんの問題は,本当に問題の定義をプログラムとして書き下すだけで,後は制約ソルバーがやってくれます.ただ,後述しますが,ライブラリを使えば,言語機能を使えば 「〜ができる」 ということは,本質ではないと私は思います.

また,数学という WhatToSolve をそのまま記述を謳って置きながら,結局は HowToSolve にひきづられたプログラムじゃないとまともには動かない場合も多いです.

って、なんか、それでいいのか。ライブラリが多いっていうのはまあ、当然として、ghcでコンパイルしてるからっていうのはおかしいんじゃないだろうか。lazyでpureな物は最近の研究が進んだこととか、遅延がうまくいくのとかが重なって、「Cで書かれたものと同等か、それ以上の速度が出る」んじゃなかったっけ…確か。

特殊なケースでHaskellのほうが遅くなるっていうんだったらわかるけど、コンパイラという分野で遅いっていうのは、さすがに「大体の場合でCよりは遅い」と言うしかないんじゃないだろうか。

まあ、速度以外のあらゆるものを放棄したCと比べるのはいけないかもしれない。処理系による速度の差が問題になることなんて滅多に無いかもしれない。僕も貧乏性プログラマを名乗ってはいるけど、面倒なときはパフォーマンスよりも簡単さを選ぶことだってしょっちゅうだし、その簡単さをありがたいとも思う。

けど、だけど、過剰宣伝というか、そういうのはどうかと思うのである。

っていうのが、まあ、Haskell学んで一日目の何の発言もする権利も持たないような糞初心者が思っていることを吐き出しただけのものです。適当に流してください。
(J - ■Haskeなんとか)

なんでかというと,プログラムの抽象度が低い (理論的モデルが窮屈なため) ため,最適化のための工夫の余地が限定されてしまうからなんですよね.WhatToSolve と HowToSolve の分離が不十分なため,どちらも中途半端になっています.

これは,Prolog と同根の問題です.アレも What を謡いながら,やっていることは How の記述という,捻じ曲がった変態言語ですから.確定節でも論理学でも何でもなくて,最終的に残るのは,カットまみれの不気味で変わり果てた仕様の残骸だけ.

まぁ,こういうことを書くと,「〜というライブラリ/フレームワーク/言語機能を使えばカンタンにできるぜ」という,自分の頭の良さと言語の素晴らしさを披露したくてしたくてしょうがない,特定の言語マンセーな人たち (Perl や Haskell の人に多い) に集中砲火されそうですが.

そういう問題では無いと思うのですよ.

# あと,言語が素晴らしいかと,GC とか 高階とか,演算子オーバロードみたいな各言語機能が素晴らしいのかを区別しない議論が多すぎる.まぁ,全体は部分の総和以上なのですが.別にその言語に特別なものじゃないのに,マンセーしている信者を見ていると,なんだかなぁと思うわけですよ.

ET パラダイムは,それぞれの工程,仕様記述,プログラム記述,変換技術,実行技術,その他もろもろの要素技術は,それほど重要視していません.

# や,ボスはけっこう ET マンセーな人で,私なんかはたまに辟易してしまうのですが w 少なくても,パラダイムの大局的な (論文などに書く,公的な) 視点としては.

重要なのは,何らかの仕様記述手法があって,そこから様々な要素技術を用いて,仕様に対して正当かつ効率良く実行可能なプログラムを得る,という「王道」を何とかして確立することなのではないか,とこのシュトロハイムは思うよ.

仕様記述というと,やたら形式的で重厚で役に立たないもの,というのを想像する人がいるかもしれませんが,実は正規表現だって,アドホックな仕様記述手法だと私は思いますよ.

みんな,わけのわからない記号だらけの仕様から,ちゃんと文字列を受理するオートマトンを自動生成し,活用しまくっているではありませんか.

あれは,動かすことができる仕様に他なりません.そして,動かしてみて,上手くマッチしないな,とか,いろいろ実験を繰り返しながら,仕様を改善していくわけです.

そしてまさか,生成されたオートマトンのバイトコードを編集する人はいませんよね.みんな仕様しか見ないし,編集しません.

言語の機能はどうでも良くて,ライブラリで全部やろうという思想も,究極的には,プログラムなんてどうでも良くて,仕様を記述するための枠組みの構築を重視しようという思想の裏返しだと思います.きちんと認識している人は少ないのかもしれませんが.

… う〜ん,発散してきた.

また,私は関数型言語に関してはシロウトなので,かなり間違ったことを言っているかもしれませんが,言いたいことは,要素技術は大事だけど,もっと本質的なことがあるんじゃないの ?

多少プログラムが抽象的になって,仕様に近づいて,検証が容易になったからといって,結局人間がひらめきと勘でプログラムを書かないといけないことには変わりないんじゃないの ?

コンパイラを通ったら 100 % 未定義の動作をしないというのは素晴らしいことだけど,じゃあ,その,コンパイラに通すための肝心要のプログラムはどうやって作るの ? 結局職人技じゃないの ?

ある程度確立された問題領域に対しては凄く強くて,Prsec は確かに素晴らしいのかもしれないけど,全く未知の問題領域,ライブラリが存在しないような領域に対して,純粋関数という強烈な檻の中で,狭いプログラム空間の中で,本当に適切な解を見つけることができるの ?

できたとしても,それは自然なの ? 単に,Haskell が凄いんじゃなくて,Haskell を使う人が超人ってだけなんじゃないの ? その人の頭の中では,かなりアクロバティックなブラックマジックで無理やり解決してるんじゃないの ?

純粋関数はメインストリームの銀の玉になるの ? たんにプログラマのハードルを著しく上げるだけなんじゃないの ? そもそも Haskell を使いこなせるような人は,たぶんどんな言語でもそれなりに使ってしまうよ.技術ってのは,だれがやっても同じにならないと,あんまり意味無いんじゃないの ?

いや,もちろん,コーディングではなく,真のプログラミングは,デザイン (意思決定の連鎖) に他ならないので,仕様を書くためには,問題領域の知識は必須なわけですが,それ以外の余計な技術を山ほど学ばないとプログラムが書けない世界になったとして,みんな幸せになるの ?

僕はちょっとした使い捨てプログラムを書いたり,Windows の GUI の窓を一個出すためだけに,いちいち一意型だのモナドとかなんとかなんて学びたくないよー.

# ていうか,そもそも僕はプログラミングとかコンピュータとか数学の才能も無いし,あんまり好きじゃないよー.数学ができる頭が良くて良くてしょうがねぇ人たちからみれば,こういう駄目人間は死ねば良いってことなのかもしれないけど.自分達さえ快適にプログラミングができれば幸せなのかもしれないけど.

ってことかも.

というか,ぶっちゃけ,私はこんなこと研究したくは無いんですよ.誰か,もっと優秀な,他の人にやってもらいたいというのが本音です.基本,過去のエライ人たちにただ乗りフリーライダーな人間なので,がんばりたくないけど幸せになりたいんですよ.

本来ならば,私みたいな,人生の前半をゴミ箱に捨てて,大学でようやくコンピュータに触れ,数学や物理はおろか,情報理論や計算機科学の基礎的素養すら不十分な DQN がやるようなことじゃないんですよ.

しかし,私よりも何十倍も優秀なはずの人たちはみんな,なぜかこのような大きなビジョンからは目をそらし,要素技術の研究に夢中です.きっと論文が書きやすいのでしょう.

あるいは,現代の錬金術と言われて久しい,二大ドンキホーテ,AI とプログラム合成を研究している,なんて言ったら,研究者としてはかなり冷や飯を食わされてしまうとか,いろいろ大人の事情があるのかもしれません.僕子供だからわかんないけど.ワイルズはフェルマーの最終定理を解くために 7 年間屋根裏部屋に引きこもったらしいですし.

しかたが無いから,私のような何の才能も無いド低脳が,人生をすり減らしながらしぶしぶがんばっているわけですが.

僕は本質的に真性駄目人間なので,テキトーに軽音の仲間と部室で楽器かき鳴らしたり,焼肉食いに行ってビール飲んで騒いだり,近所のお姉さんと飲みに行ってたわいも無い話をしたりとか,そういうことばっかりしてダラダラ生きて生きたいんですよ,本当は,

巨大な野心に潰されそうになったり,必至こいて先が見えない研究の不安感に立ち向かったり,コツコツ英語論文読んで悩んだり論文書いたりとか,そういうタイプの立派な人間じゃないんです.小さな小さな田舎生まれの芥子粒みたいなゴミなんですよ,わたしゃ.

何度も書いてますが,この blog は,エライ人,あるいは優秀な若者に対して,なんらかのメッセージが届けば,僕みたいな人間でも生きてきたかいがあるかも ? という,なんともはかない希望にすがって書いているのですなぁ.

早く僕みたいな小物ががんばらなくても,偉い人たちがちゃんと正しい方向に世の中が動かしてくれて,世界中みんながグダグダしていてもちゃんと世の中が回るような世界になって欲しい.

あくせく日進月歩の技術に追われて,人間をすり減らして,何のための技術か !

この業界は,自分の優秀さや頭の良さをアピールしたいやつらばかりで,本当にうんざりする.何冊も何冊も専門書を読んでバットノウハウを溜め込んだあげく,こんな基礎文献も読んでないのかと素人を小バカにして,ちょっとトンチンカンなことを言っただけで,「イタイ」だの「厨房」だの 「めでてーな」 だの罵倒して楽しいのか ?

そんな世界も考え方も,根本的に間違っている.知識とか技術とかってのは,他人を小ばかにして優越感に浸るためのものでは無い !

なるべく何にも知らなくても,何年も何年も職人芸を磨いた天才だけが黒魔術を使えるんじゃなくて,それなりに勉強すれば凡人でも凄いことができるようになる,そんな夢を実現するための手段とか,そういうものが本当の技術なんじゃないか ? C++ の boost を使いこなせるとか,template metaprogramming ができるとか,そんなのはある意味どうでも良いことだ (じゃすとふぉーふぁんぷろぐらみんぐやホビーノウハウとして,ならば良いけど,というか,私も大好きですけど w).重要だけど,何か新しい凄いことができるということが重要なのであって,技術 (テクニック) そのものは重要じゃない.そこらへんを取り違えてはいけないと思う.

ふじさわさんのメッセージ。 - 「プログラミングは難しい」 より

> 早く人間に成りたーい。right
>
> 『10日で覚えるシリーズ』を読むプログラマの存在に耐えられない、本物志向の技術者はどれぐらいいるだろう?自分はバッタもんプログラマだから、とにかく、なんかソースコードを書いてみようという動機が湧いてくればどんな本を何時読んでもいいと思える。

この人の日記、すごく優しいなぁと思いながらいつも読んでる。しかも優しいだけじゃなくて、深く、鋭い。ぼくが、「プログラミングは難しいよ?」というお話で表現したかったことも、この人が言うことを多分に含んでいる。

プログラミングは、たしかに難しい。でも難しいだけじゃなくて、問題を前にして悩む人たちを、とても孤独にする。「馬鹿」であるとか、「正しさ」であるとか、そういう言葉が簡単に使われすぎている。この世界に足を踏み入れる人は、何年も何年もそういうことに堪えなければ、見通しの利く丘まで歩を進められない。

この旅では、「お互い様☆」と言ってくれる人なんてほとんどいなくって、我先にと、みんなみんな先へ進もうとする。何かから逃げるように。目の色を変えて。だから、ぼくにとって、「プログラミングは難しい」。あるいは、「この世界はしんどい」。

そう。しんどいんだよ。これから始めようとする人には、それがしんどいものだと伝えたい。ぼくが言いたいことの1つは、「そのしんどさを知ってもらったうえで」ということ。そこには魅力的な人がいる。魅力的な問いもある。しんどいながらも、眺望のよい道、気持ちのいいルートというのが存在する。もしあなたが、この旅を往くのなら、それを知ってほしい。そういう楽しさを共有できればなぁと思うのです。

ちなみに,私の県立大学での学生生活も,まさしくこんな感じでした.

メッセージ。 - プログラミングは難しいよ? というお話
メッセージ。 - プログラミングは難しいよ?というお話 その2
メッセージ。 - 「プログラミングは難しいよ?」 というお話 その3

私は大学に入って初めてコンピュータとインターネットに触れたような超田舎モノだったので,いろいろ大変でした.Windows にすらさわったことなかったのに,いっぱつめがいきなり,さんそらりすわーくすてーしょんとかいうわけのわからないこんぴゅーたでした.うちの大学は,一年目からいきなり研究室に配属されて UNIX 演習に C 言語演習,一発目の講義が 「こんぴゅーたあーきてくちゃ」「おぺれーてぃんぐしすてむろん」だの「ぷろぐらみんぐげんごこうぞうろん」だの.

その後 AI 系の研究室に進み,うんざりするほど大量の要素技術と格闘した後,「こりゃ駄目だ」 と計算機科学と AI の基礎のあやふやさに絶望,ET の門を叩いて,現在に至るわけです.たまたま県立大学の G 研究室の M 教官が,ET 傘下だったもので.人の縁とは不思議なものです.

結論 : つまり,僕は研究者とかに向いてないし,本当は研究とかもしたくないから,誰かもっと優秀な人たちがんばって.

今のままの流れでいくらがんばっても,計算機の世界に未来は無いよ,たぶん.ちょっと面白い言語なり技術なりが生まれては消え生まれては消え,諸行無常なだけ.かものちょうめい.

いやま,それでも良いっちゃ良いんですが.てきとーに御飯が食べられれば良いよ,もう.できれば 9-5 時勤務で,週休二日で (こんなことさえも贅沢に感じられるような世界に,誰がしたんだ ! 日本人は不遇のくせに働きすぎた.みんなが立派過ぎるから,僕みたいなクズは生き難い.もっとグダグダ生きようよ,みんな.NEET になろうぜ !)
研究TB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

今のところ研究の進捗状況はこんな感じ

2006/06/28(水) 14:58:36

ちょーありがちなサンプル.

階乗 factorial を計算する等価変換ルール

(fact 0 *F) --> (= *F 1). // fact 0 = 1
(fact *N *F),
{(> *N 0)}
-->
(:= *N1 (- *N 1)), // n--;
(fact *N1 *F1),
(:= *F (x *F1 *N)). // fact n = n * fact n - 1

を末尾再帰で書くと,

(fact 0 *A *F) --> (= *F *A).

(fact *N *A *F)--> (:= *N1 (- *N 1)), (:= *A1 (x *A *N)), (fact *N1 *A1 *F).

こんな感じになる.

*A は途中結果を保持しておく accumulater.初期値は 1 だから,(fact 10 1 ?) みたいな呼び出し方になる.

# インタフェースがわかり難いから,Prolog とかでは普通 (fact *N *X) --> (fact *N 1 *X). みたいなラッパをかます.

んで,これが ETI に読み込まれると,内部的には S 式で保持されてる.

(as (fact 0 *A *B) : (= *B *A))
(as (fact *C *D *E) : (:= *F (- *C 1)) (:= *G (x *D *C)) (fact *F *G *E))

S 式 + パターンマッチ + 論理変数さえあれば,そうとういろんなことがやりたい放題.

そして,こいつをいろいろゴニョゴニョプログラム変換して (一応企業秘密),部分評価 (まだ unfold 程度) して,出てきたプリミティブな D ルールは,こんな感じ.

(as (fact3 *Q *R *S) :
(fact31 *Q *R *S))

(as (fact31 *T *U *V)
(not (== (n 0) 1 *T *U *V)) :
(deref 2 *T *U *V (n *W))
(deref 1 *T *U *V (n *X))
(:= *Y (x *W *X))
(:= *A2 (+ 2 *T))
(getArrayElement *U *A2 *B2)
(setArrayElement *V *B2 (n *Y))
(deref 1 *T *U *V (n *B1))
(:= *D1 (- *B1 1))
(:= *C2 (+ 1 *T))
(getArrayElement *U *C2 *D2)
(setArrayElement *V *D2 (n *D1))
(fact31 *T *U *V))

(as (fact31 *F1 *G1 *H1) :
(:= *I1 (+ 2 *F1))
(getArrayElement *G1 *I1 *J1)
(:= *K1 (+ 3 *F1))
(getArrayElement *G1 *K1 *L1)
(setArrayElement *H1 *L1 (p *J1))
(getArrayElement *G1 *F1 *M1)
(:= *N1 (+ *M1 1))
(setArrayElement *G1 *N1 TRUE)
(setArrayElement *G1 0 *M1))

(as (fact32 *O1 *P1 *Q1) :
(deref 2 *O1 *P1 *Q1 (n *R1))
(deref 1 *O1 *P1 *Q1 (n *S1))
(:= *T1 (x *R1 *S1))
(:= *E2 (+ 2 *O1))
(getArrayElement *P1 *E2 *F2)
(setArrayElement *Q1 *F2 (n *T1))
(deref 1 *O1 *P1 *Q1 (n *V1))
(:= *X1 (- *V1 1))
(:= *G2 (+ 1 *O1))
(getArrayElement *P1 *G2 *H2)
(setArrayElement *Q1 *H2 (n *X1))
(fact31 *O1 *P1 *Q1))

ここまでくると,何もかも展開されて融合してるから,わけがわかりませんが… この何段階か前のレイヤーまでは,ランタイムルールが機能ごとに分割されていて,もう少し抽象度が高いです.

(全て私が手書きしたのですから,当たり前ですが.全部こんな素の,機械語レベル (見た目は S 式ですが,やってることはデータ参照と算術計算と配列操作のみ) のビルトインルール剥き出しで書かれていたら,保守拡張できるわけがありません.出ているのは,あくまでも最終結果のみです)

これをテキトーに fold して (ETI の上で動かしていろいろするために unfold していたのを,余計な中間変数を排除して,C コンパイラに最適化をがんばってもらうために再び fold) C にトランスレートすると,こんな感じになる.

#include "et.h"

void fact3(word base, word stack[], word heap[]) {


goto fact31;


fact31 :

if(ideref(1, base, stack, heap) == 0)
goto fact311;

heap[stack[2 + base]] = INT;
heap[stack[2 + base] + 1] = ideref(2, base, stack, heap) * ideref(1, base, stack, heap);
heap[stack[1 + base]] = INT;
heap[stack[1 + base] + 1] = ideref(1, base, stack, heap) - 1;

goto fact31;


fact311 :

heap[stack[3 + base]] = PTR;
heap[stack[3 + base] + 1] = stack[2 + base];
stack[stack[base] + 1] = INT;
stack[stack[base] + 1 + 1] = 1;
stack[0] = stack[base];

return;

fact32 :

heap[stack[2 + base]] = INT;
heap[stack[2 + base] + 1] = ideref(2, base, stack, heap) * ideref(1, base, stack, heap);
heap[stack[1 + base]] = INT;
heap[stack[1 + base] + 1] = ideref(1, base, stack, heap) - 1;

goto fact31;


}

C 言語って,本当に記述が簡潔な言語ですよね (笑)

ここでは末尾再帰になってるから,単なる goto しか出てこないけど,一般的には(再帰的)関数コールのためのスタックポインタ (base) のシフトとかいろいろやらないといけない.

んで,こいつをテキトーにファイルに出力して gcc -shared fact3.c -o fact3.dll とかコンパイルして共有 dl が生成されます.

そして,これをインタフェース etc から動的に呼び出すことができます.もちろん etc の再コンパイルは一切必要なし (とりあえz,同じディレクトリの中に lib ってディレクトリが切ってあって,その中にいろんなコンパイル済み dll が入っている).

$ LD_LIBRARY_PATH=./lib ./etc
[D] > (fact 10 1 ?)

----------------------------------------------------------
Dynamic linking : fact3.dll

call : fact3

Remove : fact3.dll

// 結果の表示 (デバッグ用)

{ 4 2 13 18 23 } // スタック (全てヒープへ
のポインタ(配列 index).先頭は使用長)


{4 fact 0 3628800 3628800} // スタックのプリティプリ
ント

// ヒープ (一つの要素には,ワードに乗るサイズのオブジェ
クトしか書き込めない.型タグとかも,単なる enum)

Array : {29, CONS, SYM, 6, PTR, 12, STR, 4, 'f', 'a',
'c', 't', CONS, INT, 0, PTR, 17, CONS, INT, 3628800,
PTR, 22, CONS, INT, 3628800, NIL, 0, STR, 1, '?'}

// ヒープのプリティプリント

Array : {

length : 29


1 cons
2 (sym (p 6))
4 (p 12)
6 str
7 length : 4
8 "fact"
12 cons
13 (i 0)
15 (p 17)
17 cons
18 (i 3628800)
20 (p 22)
22 cons
23 (i 3628800)
25 ()
27 str
28 length : 1
29 "?"
}

// 結果の S 式表現.面倒なので,引数として与えられたデー
タのコピーとかやってないので,副作用バリバリ.引数が書き
換わっちゃってる.

(fact 0 3628800 3628800)
----------------------------------------------------------

まだ型推論とかメモリイメージの静的解析みたいな,メタ計算 (一番肝心な部分 !! 論文になる部分 !!) は全然やってなくて,変数に型すら再構築してないから deref とかやたら出てきて気持ち悪い.

(なら,もう少し真面目にやってください)

しかも,無駄なラッパルールがそのまま出力されてる.

(でも GCC は賢いから,こういうの人間がぱっと見てわかるレベルの無駄は全部潰してくれる… と良いなぁ)

まぁ,deref は

static inline int ideref(word x, word base, word stack[], word heap[]) {

word ptr = stack[x + base];

while(1) {
if(heap[ptr] == INT)
return heap[ptr + 1];
else if(stack[x + base] == PTR) {
ptr = heap[ptr + 1];
continue;
}
abort();
}
}

みたいな,単なる繰り返し文だから,そんなのコストは高くないとは思うけど (惰性で書いてるけど,たぶん inline 展開できる大きさの関数ではない.無視されるだけ).

まぁ,今のところ,fact に特化したコードジェネレートとかをしているから,かなりいろんなところを書き直したり追加していかないといけない.

やることが腐るほどありすぎる.一応,ハリボテは出来たかな,というレベル.まだ何にも難しいことはしてない.誰でも手さえ動かせばできること.

というか,バックエンド部分は目的によって適した設計が全然変わってくると思います.


今のところは,どーんと生のメモリの塊 (heap) を reader に渡して,そのワードの配列に S 式を表す文字列を内部形式にエンコードしてそいつを操作するためのポインタを stack に格納して,動的に dll をリンクして関数コールしてあれこれする,というやり方を試してます.

C 言語で直接拡張ライブラリを書くことも可能で,しかも設計思想がシンプルなので,かなり簡単です.

ただし,C 言語で,いろんなライブラリの関数を直接呼び出すような形でプログラミングを行って dll を書くだけでは,柔軟性に乏しくなってしまいます.

できるだけ ET の D ルールでライブラリを書いておけば,部分評価とか融合変換みたいなことが簡単にできて,保守性や拡張性が格段にアップします.

人間ではとてもメンテナンスできないような,goto や switch case だらけの巨大な関数を難なく生成して,一つの dll としてまとめ,一回の関数呼び出しで一つの処理を終わらせることができるようになるので,オーバーヘッドがかなり減ります.

そしてこれらの技術は,将来的には,プログラムの仕様からの自動合成へとつながっていくことになるでしょう.

(わーお,バラ色の未来だね)
(ほんまかいな)

ワンランナーの処理をどれだけ速く処理できるか ? ということしか考えてないので,メモリのアロケートとかは一切行ってません.

最初にがばっと確保して,関数コールして例えば CGI で HTML を出力したら,後は全てまとめてメモリ領域を捨てると.

これにより,GC などのメモリ管理が一切不要になるので,極限までバックエンドがシンプルになります.

まぁ,今時の環境は,死ぬほどメモリあるんだから,ぶっちゃけ 8 割以上の状況では,GC なんて,実はいらなくね ? という逆転の発想です.

一つの処理ごとにメモリをまとめて確保 & 解放,万が一処理の途中で足りなくなったら,realloc みたいな,テキトーなノリでも,大部分は問題無いのではないかと.

このやり方には,メモリリークみたいな,深刻なバグが起こらないというメリットがあります.あと malloc とか new とかは,実は場合によっては GC よりも遅くなるから,なるべくしないのが望ましい.

そんなこんなで,今時の CPU の性能を最大限に生かすため,下手な小細工は行わず,なるべく計算資源を潤沢に使う,富豪さとシンプルさを重視した設計となっております.

(悪魔の辞典 : 作者ができるだけ実装を手抜きするため)

なんと,型タグに word (int32) 一個使うという,傍若無人ぶり.

たかが cons セル一個が,cons tag ・ car tag ・ car value ・ cdr tag ・ cdr value と,word 5 つ,20 byte も使います.

なんともやる気の無い実装.

文字列も,char じゃなくて,内部的には int32 の配列で持ってます.ascii コード前提で reader とか printer が書かれていて,printf とかがハードコードされてるから,全く意味は無いのに.

(なぜ管理人が執拗に UCS-4 にこだわるのか,これでバレちゃったなぁ,えへへ.最小限の修正で無駄を正当化するため w)

ていうか,C 言語が,自由なようでいて全然自由じゃないんだよなぁ.いや,手段はいくらでもあるんですが,どれもこれも泥臭くて変態的なキャストとかビットシフトとかを駆使しないといけないから,私のようなへたれからすればイヤーンな感じ.

こういう変態的なプログラミングをずっとしていると,制約がきつくてきつくて,むしろ機械語を直接書くほうが,ポータビリティは無くなっちゃうけど,楽なんじゃね ? とかいう,どうしようもなく時代錯誤な思想が沸いてきて良くない.

C-- ってどうなんだろうなぁ.全然知らないけど.

まぁ,全部 Byte (char の typedef とか) の配列で持って,無理やり (int)(a + i) とかポインタをキャストして,自前でポインタ演算 (使用バイトぶんだけ Byte 配列 index を進める) して,ってやり方もありだけど…

細かいことばかりにこだわっていないで人間的になろう。 -- Jamie Zawinski

修正が面倒くさくてやる気が起きないintel 32 アーキテクチャでは,効率的にいろいろ疑問が残りますし.

というか,進捗状況をかせいでボスから破門されないためにテキトーにひたすらやっつけでコードを書いていくというのはよくないなぁ,とか思った.

まぁ,うだうだ考えているよりも,手を動かして初めてわかることも多いから,ボスの多少実装至上主義的な考えは正しいとも思う.

一番あたまが痛いのが,レイヤーの設計というか,どこで切り分けるか.

一つのレイヤーで,あんまり最適化をやり過ぎると,他のレイヤーでそれ以上の最適化が困難になったり,十分な最適化がかからなくて,全体的には非効率的になったりしてしまう.

なるべく全体の流れを重視して,いかにして体系的に,自然に滑らかにコードを変換するかを考慮しつつ,それぞれの部分の要素技術もいっぱい勉強しないといけないという.

んで,そういうのが大変だから,ついついトリビアルな実装技術に現実逃避してしまう… orz
研究TB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

それなりに研究もやってます

2006/06/22(木) 21:46:30

とりあえず,インタフェースを起動して,表示されるプロンプトに D アトムを打ち込むと,文字列を内部形式に変換して,コンパイル済みの C オブジェクトコードをダイナミックリンクしてコールして処理結果を出力するような,read-eval-print loop を提供するインタフェースは作った (投げやりプロトタイプ).

$ ./reader
[D] > (app ("str" symbol 1 -2 3) (a b c) *L)

----------------------------------------------------------
Dynamic linking : app3.dll

call : app3

Remove : app3.dll

(app ("str" symbol 1 -2 3) (a b c) ("str" symbol 1 -2 3 a b c))
----------------------------------------------------------

ようし,後は,ET 言語の D ルールを極限までプリミティブに最適化するメタ計算システムと,それを C 言語に変換するトランスレータを熟成させていくだけだ !!

(ていうか,それが本丸です… ここまではトリビアルなコーディング.研究以前)

(一番肝心なところが,まださっぱり)

まぁ,例えば

(as (app () *Y *Z)
:
(= *Y *Z))

(as (app (*X | *Xs) *Y *Z)
:
(= *Z (*X | *Z1))
(app *Xs *Y *Z1))

みたいな D ルールが

#include "etc.h"

void app3(word base, word stack[], word heap[]) {

app31 :
if(!(stack[1 + base] == NIL))
goto app32;

setPtr(heap, stack[3 + base], stack[2 + base]);

return;

app32 :
if(heap[stack[1 + base]] == CONS) {

setPtr(heap, stack[3 + base], stack[4 + base] = makeCons(heap));
setPtr(heap, stack[4 + base] + 1, stack[1 + base] + 1);
setPtr(heap, stack[4 + base] + 3, stack[3 + base] = arrayAllocate(heap, 2));

stack[1 + base] = heap[stack[1 + base] + 4];

goto app31;
}
}

みたいな感じにコンパイルされるという感じ (内部的な表現形式とかはこれから変わりまくるかも).

これは人間 (私) が手書きしたコードなので,まだ若干抽象度が高いですが,本来はもう少しプリミティブな形にまで落ちるはず (全部インライン展開されるから RISC 並みにプリミティブなコード列しか残らないはず).

あと,こういうルールがたくさん組み合わさったときには,メタ計算システムで,もう少し大域的な最適化もかかるはず (というか,かけないといけない).このコードは,あくまでもほぼ 1-to-1 で,対応する形に書き下しただけのテストコードなので,原型がかなり残っており,必ずしも効率的とは言えない場合も多いと思います.

まぁ,そんなこんなで,ここまではただ手を動かしていれば良かったんですが,ここからが難しいところなんですよねぇ (´・ω・`)

(どんどん進捗状況が悪化してく予定 < 駄目院生)
研究TB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

最近のコメント

リンク

このブログをリンクに追加する

最近のトラックバック

人生の残り日数

日本人男性の平均寿命は 28700日.

RSSフィード

カテゴリー