さて、期間があいてしまいました。
クラス系をやっていたけど、少し脱線して、関数プログラミング的なものを少しやってました。
理解を深めるために、今回もjavascriptのコードを含めます。
高階関数
perlでも高階関数(関数を引数に受け取れる関数)を扱えるらしい。
記述としてはこんな感じ
1
2
3
4
5
6
7
8
9
10
11
12
13
| use strict;
use warnings;
sub hoge {
my ($foo, $a, $b) = @_;
return &$foo($a, $b);
}
print hoge(sub {
my ($x, $y) = @_;
return $x + $y;
}, 3, 5);
|
これは javascript に置き換えるとこんな感じになる
1
2
3
4
5
6
7
| var hoge = function(foo, a, b){
return foo(a, b);
};
console.log(hoge(function (x, y){
return x + y;
}, 3, 5));
|
幾分(というか、かなり)の部分で javascript の方が可読性が高いけど、
関数hogeは、第一引数に高階関数と引数a, b受け取る関数になる、
高階関数の実装は、与えられた引数x, yを加算するだけ、というシンプルなもの
perl のコードだと、&$foo となっているけど、$foo に入っているコードや文字列の実行に当たるらしい。
これに関しては以下になる
変数に与えられた関数の実行
変数に割り当てられた変数の実行は、こんな感じでできるらしい(ただし、”strict refs”になる)
1
2
3
4
5
6
7
8
| sub hoge {
my $arg1 = shift;
print "arg1 => $arg1 \n";
}
my $variable = "hoge";
&{$variable}("hello world");
|
これにより、変数$variableに割り当てられた値の実行は &$variable で行うらしい
カリー化
高階関数ができるなら、やっぱり使えて欲しいカリー化(currying)
カレーじゃない方で
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| use strict;
use warnings;
sub currying {
my ($target, $arg1, $arg2) = @_;
return sub {
my $arg3 = shift;
return &$target($arg1, $arg2, $arg3);
};
}
my $calc = sub {
my ($a, $b, $c) = @_;
return ($a + $b) * $c;
};
my $c1 = currying($calc, 1, 2);
print &$c1(3); # ==> 9
print &$c1(4); # ==> 12
my $c2 = currying($calc, 3, 4);
print &$c2(3); # ==> 21
print &$c2(4); # ==> 28
|
関数を返却されたことがわかっていれば、&$variable() で関数を実行できるらしい
これにより、引数束縛(curry)ができると。
少し、&$var が気持ち悪いけど。
これまた、js で書きなおすとこんな感じ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| var currying = function(target, arg1, arg2){
return function(arg3) {
return target(arg1, arg2, arg3);
};
}
var calc = function(a, b, c) {
return (a + b) * c;
};
var c1 = currying(calc, 1, 2);
console.log(c1(3)); // ==> 9
console.log(c1(4)); // ==> 12
var c2 = currying(calc, 3, 4);
console.log(c2(3)); // ==> 21
console.log(c2(4)); // ==> 28
|
クロージャの生成
少し戻り、クロージャの生成とその実行
高階関数ができるなら、やっぱり使えて欲しいクロージャ
やってみた。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| use strict;
use warnings;
sub closure {
my $counter = 0;
return sub {
return $counter++;
};
}
my $c1 = closure();
print &$c1(); # ==> 0
print &$c1(); # ==> 1
my $c2 = closure();
print &$c2(); # ==> 0
print &$c2(); # ==> 1
# c1
print &$c1(); # ==> 2
|
かなり素直に実行できます。
今回はここまで
次回は、リファクタリングで使える ::can とか使って
パッケージ単位で関数プログラミングです。
人はそれをメタプログラミングというらしいけど、関数言語だと結構頻繁に使えて便利なので
次回はそこにハマった人の内容になる。かも。