第81回 高階関数を理解できないとRubyは理解できない

Rubyにはブロックというものが存在する。

array = [1,3,5,9]
array.each{|i| puts i}.each{|i| print ' '; puts i*2}

結果:

1
3
5
9
 2
 6
 10
 18

このブロックは、高階関数なのである。

まつもと直伝 プログラミングのオキテ 第5回(1) | 日経 xTECH(クロステック)


eachには

{   }

と中括弧で囲むブロックを渡しているのである。
このブロックとは処理の集まりである。つまり名前のない関数と考えることができる。
そうだ無名関数だ。無名関数については、
第14回 無名関数 - bingo_nakanishiの他言語出身者のためのPerl入門
あたりで詳しく説明してきたとおり。


高階関数については、
第15回 map - bingo_nakanishiの他言語出身者のためのPerl入門
第16回 無名関数をもっと理解する - bingo_nakanishiの他言語出身者のためのPerl入門
このあたりである。



JavaScriptでこのeachを実装したければ次のようなソースを書く。
無名関数を作りだせる言語なので、このような芸当が可能なのだ。

Array.prototype.each = function(code){
  for(i=0; i<this.length; i++){
    code(this[i]);
  }
  return this;
}

var array = [1,3,5,9];
array.each(function(i){ alert(i) })
     .each(function(i){ alert(' ' + i*2) });

Perlならば、

use strict;
package Array;

sub new {
    my ($self, $list) = @_;
    my $class = ref $self || $self;
    bless $list, $class;
}

sub each {
  my $self = shift;

  my $code = shift;
  for(@$self){
   $code->($_);
  }

  return $self;
}

package main;
my $arry = Array->new([1,3,5,9]);

$arry->each( sub{ print $_[0],  "\n" } )
     ->each( sub{ print ' ', $_[0]*2, "\n" } );

結果:

1
3
5
9
 2
 6
 10
 18

といったところだろうか。

ポイント

関数に処理が渡せる。
言い換えると、関数に関数を渡せる。
これができるとプログラムの世界は広がる。


これを言語自体に「ブロック」という形で持っているのがRubyなのである。




以下は作成中の疑問....

http://perl-mongers.org/2009/01/re_map.html
を参考に、

sub each ($&) {
  my $self = shift;

  my $code = shift;
  for(@$self){
   $code->($_);
  }

  return $self;
}

で、

$arry->each{ print $_[0],  "\n" }
     ->each{ print ' ', $_[0]*2, "\n" };

と、したかったのだが、文法エラーになってしまった.....