http://www.perlmonks.org?node_id=1039758

wbirkett has asked for the wisdom of the Perl Monks concerning the following question:

Thanks to all those who offered help! Your suggestions helped me find a better solution.

use B::Deparse; # make deparsing object $deparse = B::Deparse->new("-p", "-sC"); # forward encoding transforms @fwd = ( sub {$_[0]/100, ($_[1] + 128)/255, ($_[2] + 128)/255}, sub {$_[0] * 256/25700, ($_[1] + 128) * 256/65535, ($_[2] + 128) * + 256/65535}, sub {$_[0]/100, ($_[1] + 128) * 256/65535, ($_[2] + 128) * 256/655 +35}, sub {@_}, sub {$_[0] + 116 * $_[1]/500, $_[0], $_[0] - 116 * $_[2]/200}, sub {$_[0]/100 + 116 * $_[1]/50000, $_[0]/100, $_[0]/100 - 116 * $ +_[2]/20000}, sub {@_}, sub {$_[0] * 0.4821, $_[1] * 0.5, $_[2] * 0.41245}, sub {$_[0] * 0.9642, $_[1], $_[2] * 0.8249}, sub {@_}, sub {$_[0] * 96.42, $_[1] * 100, $_[2] * 82.49}, ); # reverse encoding transforms @rev = ( sub {$_[0] * 100, $_[1] * 255 - 128, $_[2] * 255 - 128}, sub {$_[0] * 25700/256, $_[1] * 65535/256 - 128, $_[2] * 65535/256 + - 128}, sub {$_[0] * 100, $_[1] * 65535/256 - 128, $_[2] * 65535/256 - 128 +}, sub {@_}, sub {$_[1], 500 * ($_[0] - $_[1])/116, 200 * ($_[1] - $_[2])/116}, sub {$_[1] * 100, 50000 * ($_[0] - $_[1])/116, 20000 * ($_[1] - $_ +[2])/116}, sub {@_}, sub {$_[0]/0.4821, $_[1]/0.5, $_[2]/0.41245}, sub {$_[0]/0.9642, $_[1], $_[2]/0.8249}, sub {@_}, sub {$_[0]/96.42, $_[1]/100, $_[2]/82.49}, ); # CIELAB transforms sub _x2L {($_[0] > 216/24389) ? 116 * $_[0]**(1/3) - 16 : $_[0] * 2438 +9/27} sub _xyz2Lab {my $L = _x2L($_[1]); $L, (_x2L($_[0]) - $L) * 500/116, ( +$L - _x2L($_[2])) * 200/116} sub _L2x {($_[0] > 8) ? (($_[0] + 16)/116)**3 : $_[0] * 27/24389} sub _Lab2xyz {_L2x($_[0] + $_[1] * 116/500), _L2x($_[0]), _L2x($_[0] - + $_[2] * 116/200)} # make example transform sequence array @seq = ($rev[1], \&_Lab2xyz, $fwd[10]); # make combined transform # parameter: (array_of_code_references) # returns: (code_reference) sub combine { # copy transform array my @t = @_; # initialize expression my $expr = '@_'; # for each transform step for my $i (0 .. $#t) { # add to expression $expr = "\$t[$i]->($expr)"; } # return combined transform eval("return(sub {$expr})"); } # combined transform (fast and flexible, but requires initializaton (a +pprox. 75 μs)) $trans3 = combine(@seq); # deparse the code reference $body = $deparse->coderef2text($trans3); print "\$trans3: $body\n"; # call the transform @out = &$trans3(@in); print "@out\n";

The 'combine' function uses 'eval' to create a clean and efficient transform from the component parts. The overhead of this 'combine' step is equal to about 10 transform calls, which is insignificant in my application. ##### original posting ##### I need an efficient way to process a sequence of transforms. For example, here are some individual transforms as code references:

# some code references $f1 = sub {map {$_ + 1} @_}; $f2 = sub {map {log($_)} @_}; $f3 = sub {map {$_ * 3} @_};

They may be combined into a sequence

# combined transform sub trans1 {&$f3(&$f2(&$f1))}; # some data @data = (1, 2, 3); # call the transform @trans = trans1(@data); print "@trans\n";

The sequence could have fewer or more steps, so I would like to make an array of code references:

# make a sequence array @seq = ($f1, $f2, $f3); # combined transform sub trans2 { # for each code reference for (@seq) { # transform data @_ = &$_; } # return return(@_); } # call the transform @trans = trans2(@data); print "@trans\n";

This works okay, but I wonder if there is a better and faster way.