前回の
関数──Perl 6の特徴的文法
Perl 6には本当にたくさんの機能があります。ページは限られているので何を紹介すべきか迷いましたが、
Perl 6の関数にはいくつかの種類があります。そして、
関数の種類
関数には、
Sub──普通の関数
普通の関数Subは、sub
キーワードで定義します。
sub hello($name) {
"hello, $name!".say;
}
Block──実行されうるもの
Blockである{}
を用いても、
# トピック変数$_で引数を使える
my $is-even = { $_ %% 2 };
# -> 引数1, 引数2, ... の形で引数を宣言可能
my $distance1 = -> $x, $y {
($x ** 2 + $y ** 2).sqrt
};
# $^記号で明示的に宣言せずに引数を利用可能
my $distance2 = {
($^x ** 2 + $^y ** 2).sqrt
};
# for、if、whileなどもこのブロックが使われている
for 0..9 -> $x, $y {
say $x ~ $y;
}
関数Subと、return
の扱いにあります。関数内でreturn
するともちろんその関数から復帰しますが、return
すると外側の関数から復帰しようとします。すなわち、
sub even-array() {
(^10).map: { return 2 * $_ };
}
のreturn 2 * $_
はmap
に渡したBlockから復帰するのではなく、even-array()
から復帰しようとします。この例では、
sub even-array() {
(^10).map: { 2 * $_ };
}
と書く必要があります。
WhateverCode──さらにカジュアルな実行されうるもの
WhateverCodeである*
によって、
my $half = * / 2; # -> $x { $x / 2 } と等価
$half(10); # 5
# 「偶数を引数にとる」を簡潔に表現できる
sub foo(Int $even where * %% 2) { ... }
Callable──関数をまとめるロール
ここまで紹介したSub、
さて、
class Foo does Callable {
method CALL-ME($arg) { ... }
}
my &foo = Foo.new;
&foo("arg"); # CALL-MEが呼ばれる
クラスを用いれば、
引数、戻り値の宣言
すでにいくつかのコードに出てきましたが、
# 引数を宣言
sub foo($n, $s) { ... }
# 引数を型とともに宣言
sub foo(Int $n, Str $s) { ... }
# 戻り値の型も宣言
sub foo(Int $n, Str $s --> Callable) { ... }
この(Int $n, Str $s --> Callable)
のような関数の引数、
多重ディスパッチ
multiキーワードを使えば、
multi foo(Str $s) { ... }
multi foo(Int $n) { ... }
multi foo($other) { ... }
foo(10); # foo(Int $n)が呼ばれる
foo({ say "hello" }); # foo($other)が呼ばれる
この多重ディスパッチが特に威力を発揮するのはMAIN関数の場合です。
まず、
sub MAIN(Bool :$verbose, Str :$prefix = "/opt") {
say "-> verbose mode" if $verbose;
say "-> prefix is $prefix";
}
以下に示すようにオプションを簡単に扱えます。
$ perl6 script.p6 --verbose --prefix /usr/local
-> verbose mode
-> prefix is /usr/local
$ perl6 script.p6 --help
Usage:
script.p6 [--verbose] [--prefix=<Str>]
このMAIN関数は、
# pandaから一部改変して抜粋
multi MAIN('install', *@module, Str :$prefix) {
...
}
multi MAIN('list', Bool :$installed) {
...
}
こうすることで、panda install...
ならmulti MAIN('install', ...)
が呼ばれ、panda list ...
ならmulti MAIN('list', ...)
が呼ばれます。自分でサブコマンドによる分岐を書くより、
関数のラップ
関数をラップして、
sub distance($x, $y) {
($x ** 2 + $y ** 2).sqrt;
}
say distance(3, 4); # 5
# distanceをラップ
my $squashed = &distance.wrap: -> $x, $y {
# callwithによってオリジナルの関数(distance)を
# 呼び出す
callwith($x * 2, $y / 2);
};
say distance(3, 4); # 6.32...
# アンラップしてもとに戻す
&distance.unwrap($squashed);
say distance(3, 4); # 5
もしあるブロック内だけ関数をラップしたいのであれば、
{
my $squashed = &distance.wrap: -> $x, $y {
callwith($x * 2, $y / 2);
};
LEAVE &distance.unwrap($squashed);
say distance(3, 4); # 6.32...
}
# ブロックを抜けると自動的にもとに戻る
say distance(3, 4); # 5
Perl 6の関数には魅力的な機能がまだまだたくさんあります。詳しくは
<続きの
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現! - 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう - 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT