プロが教える店舗&オフィスのセキュリティ対策術

今、海外の大学に短期留学中でCSの授業をとっているのですが、その中で以下のような課題プログラムが出ています。が、Perl初心者の私にはまったく内容が理解できません。どなたか概要を解説していただけませんか?海外での英語の壁に挫折しつつあり、こちらに駆け込みさせていただきました。どうか、ご事情等ご賢察のうえ、温かいご支援をお願いいたします。

特に伺いたい点としては、以下の2点ですが全体的に解説していただけるととても助かります。

(1)この関数の呼び出し方
(2)2行目の、「my ($num, $f, @factors) = ($_[0], 2);」で、ローカル変数 $num,$f,$factors に何が初期値として代入されるのか?


sub isprime {
my ($num, $f, @factors) = ($_[0], 2);
while (1 != $num) {
if (0 == $num % $f) {
return $f == $num unless wantarray;
push @factors, $f;
$num /= $f;
} else {
$f++;
}
}
return @factors;
}

A 回答 (4件)

ANo.1 で説明の通り、引数は数値一つです。


>  @num=[4,5,6];
この代入式では、[] でくくっているので「配列の参照」を代入してます。$num[0] には、配列(4,5,6)への参照が入ります。$num[1]以降は何も無し。

> isprime(@num);
perlで関数呼び出しの引数に配列を指定した場合、配列は展開されます。この場合、@numの要素数は1つなので、isprime($num[0]) と等価。isprime は引数に数値を期待しているのに、この呼び出し方では配列への参照を与えているので、正しく動作しません。

> @num = ( 4,5,6 ); isprime(@num);
だったら、isprime(4,5,6)と等価になるので、問題なく動作しますが、引数で意味があるのは「4」だけです。5と6は無視されます。


isprimeは数値引数を取りますので、呼び出し方は、
> $result = &isprime(12);
もしくは
> @result = &isprime(12);
のどちらかになります。

wantarray は、返値を配列かスカラーか、どちらの形式で要求されているかを示します。
wantarrayは配列コンテキストで真になりますので、
上記呼び出し方法のうち、前者の場合は
> return $f == $num unless wantarray;
このreturn が実行され、

後者の場合はこのreturnは実行されませんので、最終行の「return @factors;」が実行されます。

この回答への補足

詳細なコメントありがとうございました。頂戴したアドバイスにしたがって、プログラムを実行してみたところ、このような結果となりました。
ケース1のスカラー変数の場合、引数に12を指定すると、turn値が受け取れていないようでした。また、return値を配列に格納した場合には、また違った値が格納されています。これはなぜでしょうか??呼び出し方、もしくは、値の印刷の仕方が悪いのでしょうか??教えてください。


(以下のとおり、スカラーor配列×素数、素数以外で関数を呼び出し)

ケース1:スカラー変数
$result_prime = &isprime(5);
$result_non_prime = &isprime(12);
print "scalar context :isprime(5)=$result_prime, isprime(12) =$result_non_prime\n\n";

ケース2:配列
@result_prime = & isprime(5);
@result_non_prime = &isprime(12);
print "list context :isprime(5)=$result_prime[0], isprime(12)=$result_non_prime[0]\n\n";

(実行結果)
ケース1:
scalar context :isprime(5)=1, isprime(12)=
ケース2:
list context :isprime(5)=5, isprime(12)=2

補足日時:2008/06/16 14:25
    • good
    • 0

ANo.2 で書いた通り、この関数はスカラーコンテキストかリストコンテキストかで、全然別の値を返しています。



呼び出し方は間違えてないですが、返値の表示方法がちょっと間違えてます。isprimeの動作をテストするなら
foreach my $arg ( 5, 12 ) {
print "isprime($arg)\n";
my $result = &isprime($arg);
if ($result) {
print "\$result is true\n";
} else {
print "\$result is false\n";
}
my @result = &isprime($arg);
print "\@result = (@result)\n";
}
とでも実行してみてください。
    • good
    • 0
この回答へのお礼

ありがとうございます!早速試してみたところ、素数でない場合には、因数分解した値がリストで表示されるんですね~。ようやく、問題の意図が理解できたような気がします。頂いた動作テスト手順を実行してみて、目からウロコが落ちました。

Perlって、、、いろいろ省略できたりしてなんだかお手軽に使える言語だと耳にしていたのですが、いやいや、かなり難解です。

本当にありがとうございました。しばらくは、Perlで苦戦していると思いますので、また機会がありましたらいろいろご指導賜りたく、よろしくお願いいたします。

お礼日時:2008/06/16 16:03

(1) う~ん, サブルーチンの名前から想像してほしかったんだけどなぁ.... 1個の整数が必要です.


(3) wantarray について調べてみましたか?
(4) もちろん返り値を覚えておく必要があるなら, 変数を用意して代入する必要があります.
とはいうものの, はっきりいってこのサブルーチンは出来がいいとはいえない. 特に wantarray が真のときの動作が, 名前から想像できません.
    • good
    • 0
この回答へのお礼

ありがとうございます。プログラミングのセンスがないことは承知していたのですが…やっぱり苦戦しています。本当に助かりました。どうもありがとうございました。

お礼日時:2008/06/16 14:24

(1) サブルーチンに渡す引数は配列 @_ に入ります. このサブルーチンでは $_[0] を使っていますが, これは「配列 @_ の最初の要素」を意味しますので, 少なくとも 1個の引数が必要です.


(2) my は無視して考えてください. すると
($num, $f, @factors) = ($_[0], 2);
となりますが, このような場合には「対応する要素ごと」に代入がおきます. これで $num と $f の値は決定. @factors には「代入する値」がありませんが, そのようなときには空リストが代入されます. ちなみに @factors と $factors は別物ですので注意.

この回答への補足

早速のご回答ありがとうございます。感謝感激です。
(1)についてなのですが、具体的には、たとえば以下のように呼び出すということでしょうか?
 @num=[4,5,6];
isprime(@num);

あと、以下の点も教えていただけると幸甚です。

(3)return $f == $num unless wantarray; の部分。"wantarray"とは何でしょうか?

(4)この関数は、return値(配列)を返しておりますが、この関数を呼び出す場合には、変数を定義した上でそれにreturn値を代入するようなかたちで呼び出すのでしょうか? 

たとえば、以下のような呼び出し方?
@num=[4,5,6];
@result =isprime(@num);

本当に初歩的なところからの質問で恐縮ですが、どうぞよろしくお願い致します。

補足日時:2008/06/16 13:31
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!