05 ユーザー定義関数

Cindyscriptは関数型のプログラミング言語です。ほとんどのことは関数で行います。そこで,ユーザーも関数を定義して使うことになります。

たとえば,2点間の距離を求める関数が dist() として組み込み関数にありますが,三角形の周長を求める関数はありません。三角形の周長は dist() を3回使えば求められますが,いくつもの三角形で周長を求めたい場合は,関数になっていると便利でしょう。

定義のしかた

ユーザー定義関数は,f(arg):= 処理 の形で定義します。

f は関数の名前です。自由につけられますが,変数と異なり,アルファベットの大文字と小文字は区別しません。

処理は,1行で済む場合はそのままで,複数行にわたる場合は ( )でくくります。

引数

上の定義式で,arg は引数(ひきすう)というもので,関数に渡して処理させたい値です。コンマ区切りで複数指定できます。

引き渡す値がない場合は,単に() にします。

【例1】三角形の周長を求める関数 trilength() を作る。

引数は,三角形の頂点3つですから,p1,p2,p3 とでもしましょう。

dist() 関数 または 距離の演算子 || を使って,3辺の長さを合計します。

trilength(p1,p2,p3):=|p1,p2|+|p2,p3|+|p3,p1|;

使ってみましょう。

作図ツールで三角形A,B,Cを描きます。3点の座標はA.xy,B.xy,C.xy で取得できるのですが,距離の演算子 | | ではそのまま点の名前が使えるので,A,B,Cをそのまま引数に渡します。

これだけなら,わざわざ関数にする必要はない,と思われるかも知れません。どうせ1行で済むわけですから。

四角形になったらまたそのための関数を作らなくてはなりませんね。

では,三角形でも四角形でも,任意の多角形について周長を求めるようにしたらどうでしょう。

「任意の個数の頂点を引数として渡す」には リスト を使います。その名の通り,点をリストアップして,[]でくくるのです。

関数の中では,点の個数を数えて,2つずつ距離を計算して合計すればよいですね。

【例2】多角形の周長を求める関数 perimeter() を作る

perimeter(vertex):=(

n=length(vertex);

ret=0;

repeat(n-1,s,

ret=ret+|vertex_s,vertex_(s+1)|;

);

ret=ret+|vertex_1,vertex_(-1)|;

);

少し解説をしましょう。

1行目:n=length(vertex); :リスト vertex の要素の個数を求めて n に代入しています。

2行目:ret=0; : ret を0にしています。

3行目:repeat(n-1,s, :n-1 回の繰り返しですが,カウンタを s にしています。s=1,2,・・・となっていきます。

4行目:ret=ret+|vertex_s,vertex_(s+1)|;

アンダーバーsは,リスト vertex のs番目の要素を示します。順に2辺を取ることになります。

6行目:最初の点 vertex_1 と最後の点 vertex_(-1) の距離を求めて足しています。

関数の戻り値

関数で作業をさせたとき,その結果を受け取りたい場合があります。上の【例1】【例2】では,いずれも計算結果を求めています。作業した結果を値として受け取る場合,これを「戻り値」といいます。

Cindyscriptでは,特に明示しない場合,最後に行われた式の評価結果が戻り値になります。

「評価」というのは少し分かりにくい言葉ですが,計算をした場合はその結果のことです。

【例1】では,1行だけですので計算結果がそのまま戻り値になります。

【例2】では,繰り返しを行ったあと,最後に ret=ret+|vertex_1,vertex_(-1)|; を実行しました。

これを「評価」すると,ret の値がその評価値になります。

すなわち,ret の値が戻り値になるのです。

条件判断などが入っていて,最後にどれが実行されたかが不明な場合は,最後に戻り値にしたい値を単に書いておけば,それが戻り値になります。

たとえば,

function():=(

いろいろ;

ret;

);

とすれば,ret の値が戻り値になります。

関数の型

他のプログラミング言語では,関数にも「型」があります。それは,戻り値の型なのですが,Cindyscriptはでは特に明示する必要はありません。上で示した戻り値がそのまま関数の型になると考えてよいでしょう。そして,それは戻り値の型によって変動します。

引数も型の明示を必要としません。その結果どんなことが起こるか,上の【例2】で示しておきましょう。

距離を求める演算子 || は絶対値記号と同じですね。|a,b| は,b-a の絶対値(数直線上での距離)を表します。

すると,【例2】の関数 perimeter() の引数として,座標ではなく数値のリストを与えることもできるわけです。

たとえば,perimeter([3,-1]) とすると結果は 8 になります。(|3,-1|と|-1,3|の合計です)

再帰的関数

再帰的関数とは,関数の中で自分自身を呼びだす(使う)ことをいいます。

シンプルな例を示しましょう。

【例3】階乗を求める

n!は1からnまでの整数の積ですが,たとえば,4! は 4×3×2×1=4×3! となりますから,3! を使って4!が求められることになります。

そこで,次のように定義します。

fac(n):=if(n==0,1,n*fac(n-1));

動作を追跡してみましょう。

n=4のとき,4*fac(3) を実行します。前述の通りです。fac(4) の中で fac(3) を使っています。これが「再帰」です。

さて,その fac(3) は 3*fac(2) を実行します。

こんどは fac(2)が 2*fac(1) を実行します。

さらに,fac(1)が1*fac(0) を実行します。ここで,fac(0)は1ですので(if(n==0,1 です)ここで fac(1)が1と確定します。

すると,fac(2)は2になり,fac(3)は6になり,fac(4)が24になります。