あらかじめPerlに組み込まれた関数以外に、自分で関数を作ることができます。 これをサブルーチンと呼びます。サブルーチンの記述の仕方は次の通りです:
sub myfunction{ ……関数の名前 my ($var1, $var2, ...) = @_; ……関数の引数 my $i = yyy; ……関数の中だけで使う変数とその初期化 ..... ..... return (xxxxx); ……値の出力 }
実際にそれを使うときは次のように関数名に&をつけて使います (関数の定義のあとで呼び出すときはつけなくてもよいが、 つける癖をつけておいた方がミスが少ない)。
&myfunction(XX, XX, ...)
例として次のスクリプト(nm207.pl)を見てみましょう:
1: print &add(2, 3), "\n"; 2: 3: sub add{ 4: my ($num1, $num2) = @_; 5: return($num1 + $num2); 6: }
3行目〜6行目で add という関数を定義しています。この関数は2つの引数を持ち、 それらの合計を戻します。実際に使うときは $num1 に 2 が、 $num2 に 3 が代入されています。
この $num1 と $num2 は 4行目で my というキーワードをつけて、 「局所変数」として宣言されていますので、 偶然サブルーチンの外に同じ名前の変数があっても、それとぶつかることはありません。 独立して使うことができます。 例えば、次の例(nm208.pl)を見て下さい:
1: $num1 = 10; 2: print $num1, "\n"; 3: print &add(2, 3), "\n"; 4: print $num1, "\n"; 5: 6: sub add{ 7: my ($num1, $num2) = @_; 8: return($num1 + $num2); 9: } 10: 11: print $num1, "\n";
実行結果は次のようになります:
I:\nyuumon2>jperl nm208.pl 10 5 10 10 I:\nyuumon2>
&add を呼び出しても、サブルーチンの外の $num1 (こちらは「大域変数」といいます) にはなんの影響もないことがわかります。
局所変数はサブルーチンの中でよく使いますが、 ブロックの中で宣言すればその有効範囲をそのブロックの中だけに限定することができます。
もうひとつ例をあげてみます。 自然数(n)を指定して 1+2+ ... +n を計算する関数を作ることを考えてみます。
まず以前やった nm006.pl を思い出してください。 これは1から10000まで足すスクリプトでした。
1: $sum = 0; 2: $i = 1; 3: 4: while($i <= 10000) { 5: $sum = $sum + $i; 6: $i++; 7: } 8: 9: print "1 + 2 + ... + 10000 = $sum\n";
これを10000という特定の数ではなくて、実行時に指定した自然数までくわえる スクリプトに書き換えてみます。引数のチェックは省略します。
1: ($num) = @ARGV; 2: $sum = 0; 3: $i = 1; 4: while($i <= $num) { 5: $sum = $sum + $i; 6: $i++; 7: } 8: 9: print "1 + 2 + ... + $num = $sum\n";
ちょこちょこっと変えると、関数の定義ができあがります。 ポイントは @ARGV を @_ に変えること、変数を局所変数にするために my をつけること、print ではなく return を使うことなどです。
1: sub total { 2: my ($num) = @_; 3: my $sum = 0; 4: my $i = 1; 5: while($i <= $num) { 6: $sum = $sum + $i; 7: $i++; 8: } 9: return ($sum); 10: }
実際にこれを使ったスクリプトを書いてみます:
1: sub total { 2: my ($num) = @_; 3: my $sum = 0; 4: my $i = 1; 5: while($i <= $num) { 6: $sum = $sum + $i; 7: $i++; 8: } 9: return ($sum); 10: } 11: print &total(10), "\n";
ふつうのスクリプトがかければ、関数(サブルーチン)を使うのも、上のように簡単です。
サブルーチンの定義の中で、他の関数(組み込まれたもの・自作の物)はもちろん 使用可能ですが、さらに定義しようとしている関数も使用可能です(これを 再帰といいます)。下の課題の1では、再帰を使うことも 可能ですし、再帰を使わず定義することも可能です。
課題
- 与えられた整数 n の階乗 n! = 1x2x...xn を計算する関数 factorial(-) を作りなさい。 ただし、0! = 1 とします。
- 与えられたふたつの整数の組 (n,r) に対して、そのコンビネーション nCr = n!/(r!(n-r)!) を計算する関数 combination(-,-) を作りなさい。 (&factorial を使ってよい)
- 上の関数を使って、実際になにかスクリプトを作り、スクリプトと その実行結果を自分のページに載せなさい。 例えば次のようにパスカルの三角形を出力するスクリプトなどはどうですか?
I:\nyuumon2>jperl pascal.pl 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1 1 10 45 120 210 252 210 120 45 10 1 I:\nyuumon2>