descartes-src (ソースパッケージ descartes-src-0.26.0.tar.gz) | 2012-09-09 20:57 |
descartes-win (Windows用バイナリパッケージ descartes-win-0.26.0.zip) | 2012-09-09 20:52 |
会話キャラクター: ツンデレ アプリケーション (会話キャラ:ツンデレ v1.0 for Windows) | 2010-04-29 13:41 |
会話キャラクター: 2人の女の子 ダブルキャラクター (会話キャラクター 2人の女の子 ダブルキャラクター 1.0 for Windows) | 2011-10-02 22:23 |
会話キャラクター: Eliza風英語版 (会話キャラ:Eliza風英語版 v1.0 for Windows) | 2010-05-11 01:06 |
会話キャラクター: 猫耳メイド アプリケーション (会話キャラ:猫耳メイド v1.0 for Windows) | 2010-04-27 21:15 |
会話キャラクター: イライザ風日本語版 (会話キャラ:イライザ風日本語版 v1.0 for Windows) | 2010-04-30 21:53 |
経済指標表示プログラム for Windows (経済指標表示プログラム V1.0) | 2011-08-18 22:04 |
ニュースヘッドライン表示プログラム (ニュースヘッドライン表示プログラム V1.0 for Windows) | 2011-08-16 12:31 |
デカルト言語 example (デカルト言語の例題 example-0.7.0.zip) | 2009-03-01 19:47 |
電力状況表示プログラム for Windows (2011年夏版 全国電力供給状況表示プログラム V1.0) | 2011-08-15 13:25 |
さて、ここまでに、純関数とクロージャと高階関数を別々に実現してきました。 逆に言うと別々に考えてきたおかげで組み合わせて考えることも簡単です。
純関数と高階関数、クロージャと高階関数の組み合わせが考えられます。 それぞれを独立に実現してきたので、組み合わせたコンパイラは簡単に実現できます。
まず、純関数と高階関数の組み合わせについて考えてみましょう。
純関数は引数と返り値の関係に、参照透過性があり同じ引数ならばいつも同じ結果が間違いなく得られるのが特徴でした。
そこに高階関数を組みあせると、引数に設定された関数により同じ関数を実行しても動作を変えることができます。 また、返り値として関数が得られたときに、その関数の実行結果により動作を柔軟に変えることができるようになります。 しかし、ここで使われている関数はすべて純関数で構成されますので、動作は極めて予測しやすくバグなどが混入し難いでしょう。
つまり、純関数と高階関数の組み合わせによって、参照透過性を維持しながらも多彩で柔軟なプログラムを実現できると言えるのです。
ベースに四式言語である高階関数をサポートするプログラミング言語を使いましょう。 これは手続き言語に高階関数を実現したものでした。
この四式言語に、純関数言語である二式言語の改造点を加えます。 二式言語の改造点は次のようなものでした。
- 変数への代入処理を廃止
変数は、関数の引数やローカル変数も含めて代入処理で更新されないようにします。
しかし、初期値の設定はできるようにしておきます。 変数の初期化は数式で行ってもかまいません。
一度初期化して定義した変数は更新できなくなります。
<program> <setVar Line 1> <print "#include <stdio.h>"> <print "#include <stdlib.h>"> <print "typedef int (*func)();"> <print> <print "int main() "> <print "{"> {<Comment>} <block> <print "}"> {<Comment>} ; <block> [ "const" <emsg "constant name."> <printf "const int "> <ident> <emsg "constant definition."> "=" <printf " = "> <number> {"," <printf ", "> <ident> <emsg "constant definition."> "=" <printf " = "> <number> } <emsg "';' is missing."> ";" <print ";"> ] {<Comment>} { <ident #typef> ":" "function" <emsg "function name."> <printf #typef " "> <ident> <emsg "function definition."> "(" <printf "("> [<ident #var1> ":" <ident #type1> <printf "const " #type1 " " #var1> { "," <printf ", "> <ident #var2> ":" <ident #type2> <printf "const " #type2 " " #var2> } ] ")" <print ")"> ";" <print "{"> <block> <print "}"> } {<Comment>} <statement> ; <statement> <SKIPSPACE> ::sys <line #Line> <setVar Line #Line> {<Comment>} ( <ident #func> <emsg "syntax error."> "(" <emsg "function call."> <printf #func "("> [<expression> {"," <expression>}] ")" <printf ")"> <print ";"> ";" <emsg "syntax error."> | "return" <printf "return "> <expression> <print ";"> ";" <emsg "syntax error."> | "var" <emsg "variable name."> <printf "const "> <ident #var1> ":" <ident #type1> <emsg "variable definition."> <printf #type1 " " #var1> "=" <printf " = "> <expression> <print ";"> {"," <printf "const "> <ident #var2> ":" <printf " "> <ident #type2> <emsg "variable definition."> <printf #type2 " " #var2> "=" <printf " = "> <expression> <print ";"> } ";" | "begin" <print "{"> { <statement> } "end" <print "}"> | "if" <emsg "if sentence."> <printf "if ("> <condition> "then" <print ") {"> <statement> ["else" <print "} else {"> <statement> ] <print "}"> | "print" <emsg "print sentence. "> [ ( <strings #str> <printf 'printf("%s ", "'#str'" );'><print> | <printf 'printf("%d ", '> <expression> <print ');'> ) { "," ( <strings #str2> <printf 'printf("%s ", "'#str2'" );'><print> | <printf 'printf("%d ", '> <expression> <print ');'> ) } ] <print 'printf("\n");'> ";" <emsg "syntax error."> ) ; <condition> "odd" <emsg "odd syntax."> <printf "(("> <expression> <printf ") & 1)"> | <expression> ("=" <printf " == "> |"#" <printf " != "> |"<=" <printf " <= "> |"<" <printf " < "> |">=" <printf " >= "> |">" <printf " > "> ) <expression> ; <expression> [ "+" <printf "+"> |"-" <printf "-"> ] <term> { ("+" <printf "+"> |"-" <printf "-"> ) <term>}; <term> <factor> { ("*" <printf "*"> |"/" <printf "/"> ) <factor>}; <factor> ( "$" <printf "(*"> <ident #f> "(" <printf #f ")("> |<ident #f> "(" <printf #f "("> ) [ <expression> {"," <printf ", "> <expression>}] ")" <printf ")"> | <ident> | <number> | "(" <printf "("> <expression> ")" <printf ")"> ; <ident #id> <ID #id> <reserved #id> ; <ident> <ident #id> <printf #id> ; <number #sign #n> ["+" <is #sign ""> | "-" <is #sign "-"> | <is #sign ""> ] <NUM #n> ; <number> <number #sign #n> <printf #sign #n> ; <strings #str> <STRINGS #str> ; <strings> <strings #str> <printf #str> ; <Comment> "//" <SKIPCR> ; <reserved #id> <not ::sys <member #id (var begin end if then while for do function return print odd)>> ; <emsg #x> <x <getVar #Line Line> <warn "error : " #Line ":" #x> <exit>> ; <emsg2 #x> <getVar #Line Line> <warn "error : " #Line ":" #x> <exit> ; <compile> ::sys<args #x> ::sys<nth #inputfile #x 1> ::sys<suffix #outputfile #inputfile c> <print inputfile #inputfile> <print outputfile #outputfile> ::sys<openw #outputfile ::sys<openr #inputfile <program>>> ; ? <compile>;
それでは、五式言語用のサンプルプログラムを作成してコンパイルしてみましょう。
まず、「7.3 五式言語のソース」を pl05.dec と名前をつけて保存しておいてください。
次のサンプルプログラムのソースを使います。
int:function inc(n:int); begin return n+1; end int:function dec(n:int); begin return n-1; end int:function calc(f:func, n:int); begin return $f(n); end begin var a:int = calc(inc, 1); var b:int = calc(dec, 1); print a, b; end
引数を1増やすinc関数と、1減らすdec関数を定義しています。
さらに第1引数に指定された関数で、第2引数でしてされた数を計算するcalc関数を定義し、 inc関数とdec関数を引数に指定して計算した結果を表示します。
非常に簡単な例ですが関数を引数に指定することで、動きの変わる関数が定義できていることを確認してみてください。
このサンプルプログラムをf.pl0という名前で保存してコンパイルします。
$ descartes pl05.dec f.pl0 inputfile f.pl0 outputfile f.c result -- <compile> -- true
f.c にコンパイル結果が出力されました。
インデントを直してf.cを見ると次のようになります。
#include <stdio.h> #include <stdio.h> #include <stdlib.h> typedef int (*func) (); int main() { int inc(const int n) { { return n + 1; } } int dec(const int n) { { return n - 1; } } int calc(const func f, const int n) { { return (*f) (n); } } { const int a = calc(inc, 1); const int b = calc(dec, 1); printf("%d ", a); printf("%d ", b); printf("\n"); } }
関数の引数や変数の定義にconstが定義されています。
また、func型が定義されていて、calc関数の引数で使われています。
それではgccでコンパイルして実行します。
$ gcc f.c -o a.out $ ./a.out 2 0
inc関数の結果が1を1増やして2、dec関数の結果が1を1減らして0になっています。
[PageInfo]
LastUpdate: 2012-12-15 13:23:49, ModifiedBy: hniwa
[License]
Creative Commons 2.1 Attribution
[Permissions]
view:all, edit:login users, delete/config:login users