ブログトップ 記事一覧 ログイン 無料ブログ開設

サンプルコードによるPerl入門

2008-07-05

サブルーチンへのリファレンスを利用したポリモーフィズム

 サブルーチンへのリファレンスを利用したポリモーフィズムを実現したサンプルです。

use strict;
use warnings;

my @nums = (1, 2, 3);

print "1: サブルーチンへのリファレンスを使って合計と平均を順番に求める。\n";

# サブルーチンへのリファレンスの# 配列を作成。
my @calc_funcs = (\&sum, \&average); 
                                       
for my $calc_func (@calc_funcs) {
  my $result = $calc_func->(@nums);
  print "結果: $result\n";
}
print "\n";

sub sum {
  my @nums = @_;
  my $total;
  for my $num (@nums) {
    $total += $num;
  }
  return $total;
}

sub average {
  return sum(@_) / @_;
}


print "2: サブルーチンへのリファレンスを使って選択的に処理する。\n";
my $how_to_calc = 'sum';
my $calc_func;

if ($how_to_calc eq 'sum') {
  $calc_func = \∑
}
else {
  $calc_func = \&average;
}

my $result = $calc_func->(@nums);

print "計算方法 : $how_to_calc\n" .
  "結果 : $result\n\n";


print "3: サブルーチンへのリファレンスとハッシュを使って選択的に処理する。\n";
$how_to_calc = 'average';
my %calc_table = (sum => \&sum, average => \&average);

# $calc_table{'average'} には、サブルーチンへのリファレンス
# が入っているので、-> 演算子でデリファレンスして
# サブルーチンを呼び出す。
$result = $calc_table{ $how_to_calc }->(@nums); 

print "計算方法 : $how_to_calc\n" .
  "結果 : $result\n\n";

変数に対してサブルーチンを順番に適用する

my @calc_funcs = (\&sum, \&average);
for my $calc_func (@calc_funcs) {
  my $result = $calc_func->(@nums);
}

 ある変数に対してサブルーチンを順番に適用するには、サブルーチンへのリファレンスを利用します。サブルーチンへのリファレンスを配列に格納して、forループで繰り返しサブルーチンを呼び出します。

変数とサブルーチンのイメージ

|----------|
|          |<-------- サブルーチン1
|          |
|  変数    |<-------- サブルーチン2
|          |
|          |<-------- サブルーチン3
|----------|

 ある種類の引数に対して、順番にサブルーチンを適用していくイメージ。引数は固定で、サブルーチンが移り変わってゆくイメージ。

サブルーチンへのリファレンスを利用したポリモーフィズム

# if文で分岐する方法
my $how_to_calc = 'sum';
my $calc_func;

if ($how_to_calc eq 'sum') {
  $calc_func = \&sum;
}
else {
  $calc_func = \&average;
}

my $result = $calc_func->(@nums);

 ポリモーフィズムとは、「同じ記述であるのに異なる関数が呼び出される」ということを意味する言葉です。オブジェクト指向では、「オブジェクトに応じて異なるメソッドが適用される」ということを意味する場合が多いです。

 この例の場合は、 $calc_func->(@num) という記述は、$calc_func に何が代入されているかによって意味を変えます。\$sum が代入されている場合は、sum サブルーチンが呼びだされ、\$average が代入されている場合は、average サブルーチンが呼びだされます。

 javaでは、オーバーロードとオーバーライドがポリモーフィズムを実現するための方法で、C言語では関数ポインタです。

ハッシュを利用した美しい方法

$how_to_calc = 'average';
my %calc_table = (sum => \&sum, average => \&average);
$result = $calc_table{$how_to_calc}->(@nums); 

 この使用方法が関数リファレンスによるポリモーフィズムのもっとも洗練された形だとわたしは思っています。

 選択的な処理であるのに、if文をいっさい使っていません。ハッシュのキーに対応したサブルーチンを呼ぶことで、処理を分岐させています。


 

Perl逆引き辞典/サブルーチンへ

perlcodesampleperlcodesample 2008/07/06 11:46 >> miya2000さん( はてなブックマークより転載 )

> 「ハッシュを利用した」それは「window[’aert’]()」と
>「window[’confirm’]()」をポリモーフィズムと呼んでいるよう
>に見えるけど。変じゃないのかな?

 んー、自分では変じゃないと思っています。「$calc_table{ $how_to_calc }->( @nums ) 」という同じ記述が、$calc_table{ $how_to_calc } の値によって、振る舞いを変えるからです。

 window[’aert’]() っていうのは、Javascriptの記述で、Perlでいう、window{’aert’}->() と等価なんでしょうか?等価であれば、ポリモーフィズムと呼んでよいと思います。

 まぁ、ポリモーフィズムという言葉が多義的ですけれど。

miya2000miya2000 2008/07/06 13:19 反応ありがとうございます。(あんまり関係ないですが「aert」は「alert」の間違いでした)。

「等価なんでしょうか?」は等価です。また「window[’alert’]() 」は「window.alert()」と等価です。つまり関数名を文字列で渡しているということになります。
「同じ記述」でも実行する関数名(インターフェイス)が違えばポリモーフィズムとは呼ばないのではないのか? というのが見解の相違点だと思っています。

「同じ記述」で「振る舞いを変える」といえば eval が適合すると思いますが、これはいかかでしょうか? eval はさすがに「多様性」「多態性」という言葉とは次元が違うのではないかと思います。

perlcodesampleperlcodesample 2008/07/06 15:26  関数のインターフェイスが同じ場合に限定して、ポリモーフィズムと呼ぶのが一般的なんですね。

 「同一名のメソッド呼び出し」が「オブジェクト」によって振る舞いを変えるオブジェクト指向の機能と、「同一名の関数呼び出し」が「引数の型や個数」によって振る舞いを変える「オーバーロード」だけをポリモーフィズムと呼ぶべきなんしょうか?

 それだとこの記事は、誤解を招いてしまいそうです。

 今回のように「デリファレンスという操作」が、「リファレンスに指されたサブルーチン」によって振る舞いを変えるというのは、ポリモーフィズムの文脈で語らないほうがよいんでしょうか?

 デリファレンスという操作を、->dereference() みたいなメソッドとして捕らえると、一種のポリモーフィズムのようにわたしは感じてしまいます。

miya2000miya2000 2008/07/06 17:40 そこには全く依存はありません。(一般的かどうかは知りません)
 my $result = $calc_func->( @nums );
「calc_func」という「同一名のメソッド呼び出し」です。

私が変だと感じたのは「ハッシュを利用した」に関してのみです。
 $result = $calc_table{ $how_to_calc }->( @nums );

「ポリモーフィズム」と「サブルーチンのリファレンスをハッシュに管理させること」は関係ないと思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証