My First Perl#5

さて、期間があいてしまいました。
クラス系をやっていたけど、少し脱線して、関数プログラミング的なものを少しやってました。
理解を深めるために、今回も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 とか使って
パッケージ単位で関数プログラミングです。

人はそれをメタプログラミングというらしいけど、関数言語だと結構頻繁に使えて便利なので
次回はそこにハマった人の内容になる。かも。