8

In Perl 5, we can apply functional programming techniques (using closures, higher order functions like map, grep, etc.). But how about function composition? Let's say, in Haskell it can be done very easily with (.) function:

map (negate . abs) [-3, 2, 4, -1, 5]

What would be the equivalent of such "dot function" in Perl?

doubleDown
  • 8,048
  • 1
  • 32
  • 48
sigidagi
  • 864
  • 7
  • 17
  • 6
    Perhaps you should explain this dot function, so that your question does not require knowledge of both haskell and perl to answer. – TLP Aug 20 '12 at 13:10
  • @TLP Well, there's actually pretty nice explanation [here](http://stackoverflow.com/questions/631284/dot-operator-in-haskell-need-more-explanation). – raina77ow Aug 20 '12 at 13:14
  • 2
    Perhaps you could edit your question and add an explanation? – TLP Aug 20 '12 at 13:22

4 Answers4

11

Sadly, I don't know Haskell.

But function composition essentially is putting the output of one function into the next function as an argument.

output = (negate . abs)(input) is the same as output = negate(abs(input)). In Perl, parens are often optional, and the input is implicit in the map function, so we can just say

output = map (negate abs) list

Now just translate this to Perl syntax, and we have

my @output = map {- abs} (1,2,3);

for the mathematical/algebraic negation, and

my @output = map {! abs} (1,2,3);

for the logical negation (which is the same as map {! $_} (1,2,3), of course).

amon
  • 57,091
  • 2
  • 89
  • 149
10

Ok, first lets look at the function signature of (.) in Haskell:

(.) :: (b -> c) -> (a -> b) -> a -> c

This is easily implemented like this

foo :: (b -> c) -> (a -> b) -> a -> c
foo f g a = f(g a)

An implementation in Perl might look like this then

sub dot {
    my $f = shift;
    my $g = shift;
    my $a = shift;
    $f->( $g->($a) )
}

Now we implement the function negate like this

sub negate { - shift }

And we are ready to use it like so

my @foo = map { dot \&negate, sub{abs}, $_ } -2..2;
print join( ", ", @foo) . "\n";

But as you can see from the other answers, there are easier ways to do this. So what you should really ask yourself is, why would you want to. Haskel has several characteristics which make function composition really useful. In Perl however, it feels really clunky and awkward to me.

If you are interested in what kinds of functional programming Perl is actually good at, i recommend the Book Higher-Order Perl.

tauli
  • 1,420
  • 8
  • 13
  • I think it makes a lot more sense to eliminate `dot`'s last argument and let it return a function instead (namely `sub { $f->($g->(@_)) }`), so that you have `(dot \&negate, \&CORE::abs)->($_)` instead. – hobbs Sep 02 '12 at 07:31
  • Yes, returning a sub is a little less bad and gives `dot` a little bit more flexibility. But thats beside the point IMHO. The point i was trying to make is, that function composition doesn't work the same way in Perl as it does in Haskell. And instead of shoe horning some functionality in, one should instead try to figure out, what Perl can do well and use that. – tauli Sep 02 '12 at 20:22
6

I am not sure this is the answer you were seeking:

sub negate { - $_[0] }
map { negate abs } -3, 2, 4, -1, 5
choroba
  • 231,213
  • 25
  • 204
  • 289
5
sub compose {
    my ( $f, $g ) = @_;
    return sub { $f->( $g->( @_ )); };
}

sub negate (_) { - ( $_[0] // $_ // 0 ); }

my $neg_abs = compose( \&negate, \&CORE::abs );

my @negs = map { $neg_abs->( $_ ) } -3, 2, 4, -1, 5;

compose would implement a very simple version of the dot function. But as mentioned, it's not something specifically needed, unless you want to transport the function to another location.

Axeman
  • 29,660
  • 2
  • 47
  • 102