最近の更新 (Recent Changes)

2014-01-01
2013-01-04
2012-12-22
2012-12-15
2012-12-09

Wikiガイド(Guide)

サイドバー (Side Bar)


← 前のページに戻る

7. 五式言語: 高階関数をサポートする純関数型プログラミング言語

7.1 純関数と高階関数をサポートするプログラミング言語とは

さて、ここまでに、純関数とクロージャと高階関数を別々に実現してきました。 逆に言うと別々に考えてきたおかげで組み合わせて考えることも簡単です。

純関数と高階関数、クロージャと高階関数の組み合わせが考えられます。 それぞれを独立に実現してきたので、組み合わせたコンパイラは簡単に実現できます。

まず、純関数と高階関数の組み合わせについて考えてみましょう。

純関数は引数と返り値の関係に、参照透過性があり同じ引数ならばいつも同じ結果が間違いなく得られるのが特徴でした。

そこに高階関数を組みあせると、引数に設定された関数により同じ関数を実行しても動作を変えることができます。 また、返り値として関数が得られたときに、その関数の実行結果により動作を柔軟に変えることができるようになります。 しかし、ここで使われている関数はすべて純関数で構成されますので、動作は極めて予測しやすくバグなどが混入し難いでしょう。

つまり、純関数と高階関数の組み合わせによって、参照透過性を維持しながらも多彩で柔軟なプログラムを実現できると言えるのです。

7.2 五式言語の改造点

7.2.1 いかに実現するか?

ベースに四式言語である高階関数をサポートするプログラミング言語を使いましょう。 これは手続き言語に高階関数を実現したものでした。

この四式言語に、純関数言語である二式言語の改造点を加えます。 二式言語の改造点は次のようなものでした。


- 変数への代入処理を廃止

変数は、関数の引数やローカル変数も含めて代入処理で更新されないようにします。

しかし、初期値の設定はできるようにしておきます。 変数の初期化は数式で行ってもかまいません。

一度初期化して定義した変数は更新できなくなります。

7.3 五式言語のソース



<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.4 五式言語のソースのコンパイル方法

それでは、五式言語用のサンプルプログラムを作成してコンパイルしてみましょう。

まず、「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になっています。