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

I find myself faced with something I had never thought of before, now I only wonder if it can be done this way.

My goal is to be able to create a sub-ref with a stored argument, so that argument would be automatically first in the line of arguments whenever that sub-ref is executed. The following is something like what I have in mind:

my $code = \&mysub(10); sub mysub($@){ my $need = shift; my $have = 0; foreach (@_){ $have += $_; } if($need != $have){ return; } return 1; } if($code->(1,2,3,4)){ print "You had the correct number"; }

Now I realize that in that example it wasn't really necessary, but I think it illustrates what I'm looking for. Unfortunately I realize that this is probably a very unusual thing to want to do, so I anticipate that nothing like it will be possible, but one can hope :)

My thanks to those that reply.





My code doesn't have bugs, it just develops random features.

Flame ~ Lead Programmer: GMS | GMS

Replies are listed 'Best First'.
Re: subref with stored argument?
by Paladin (Vicar) on Jan 10, 2003 at 00:30 UTC
    Try this:
    my $code = sub {mysub(10, @_)}; sub mysub { # ... }
Re: subref with stored argument?
by sauoq (Abbot) on Jan 10, 2003 at 01:09 UTC

    Although the other answers are fine, there is a subtlety you might want to be aware of. Calling the function from the anonymous sub will affect the call stack. You can avoid that by using the magical goto &sub form.

    sub foo { print "foo @_\n"; for (0..2) { print join('|', caller($_)), "\n" if caller($_); } print "\n"; } my $r1 = sub { foo("bar", @_) }; my $r2 = sub { unshift @_, "bar"; goto &foo }; foo(); $r1->('baz'); # This call has an extra frame in the call stack. $r2->('baz', 'qux');

    One word of caution. Using this technique will make your prototypes pretty useless. That's OK though because usually prototypes are worse than useless anyway. You almost certainly shouldn't be using them. If you do choose to use them, you should first have a good understanding of the points raised in this article by Tom Christiansen.

    -sauoq
    "My two cents aren't worth a dime.";
    

      The only problem with using the magical goto is that for some reason it is incredibly slow.

      If performance isn't an issue, then it's fine, but if performance is an issue avoid it like the plague:)

      #! perl -slw use strict; use Benchmark qw[cmpthese]; sub recipe{ my @rice = @_; my $grains = scalar @rice; return $grains; +} sub curry { recipe( 'extra', @_) } sub spagetti { unshift @_, 'extra'; goto &recipe; } print recipe qw[1 2 3 4 5 6 7 8 9 0]; print curry qw[1 2 3 4 5 6 7 8 9 0]; print spagetti qw[1 2 3 4 5 6 7 8 9 0]; cmpthese( -10, { recipe => 'recipe qw[1 2 3 4 5 6 7 8 9 0];', curry => 'curry qw[1 2 3 4 5 6 7 8 9 0];', spagetti=> 'spagetti qw[1 2 3 4 5 6 7 8 9 0];', }); __END__ c:\test>225691 10 11 11 Benchmark: running curry, recipe, spagetti , each for at least 10 CPU seconds ... curry: 11 wallclock secs (10.41 usr + 0.00 sys = 10.41 CPU) @ 11 +838.29/s (n=123284) recipe: 10 wallclock secs (10.29 usr + 0.00 sys = 10.29 CPU) @ 15 +358.48/s (n=157962) spagetti: 9 wallclock secs (10.31 usr + 0.00 sys = 10.31 CPU) @ 75 +02.96/s (n=77393) Rate spagetti curry recipe spagetti 7503/s -- -37% -51% curry 11838/s 58% -- -23% recipe 15358/s 105% 30% -- c:\test>

      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: subref with stored argument?
by dpuu (Chaplain) on Jan 10, 2003 at 00:32 UTC
    Try using an anonymous sub:
    my $code = sub { mysub(10, @_) };
    As a matter of fact, there's nothing particularly unusual about wanting to do this: its called "currying". --Dave

      I wasn't even aware there was a term for this, but a quick CPAN search revealed a couple of modules to encapsulate the behavior, even one by our own TheDamian.

      1. Curry by David Helgason: "[The function] returns a subref to a function that calls the given function with arguments _plus_ whatever arguements are sent to it."

      2. Currying by Damian Conway: "This method call returns a reference to a new subroutine that calls the original subroutine, inserting into its argument list the prebound arguments."

      Also interesting is this remark from Helgason's module (released originally in November, 2000), "Perhaps the main reason for making this package is to avoid it being included in perl6 syntax, as per one dangerous looking RFC." And Conway's take on it: "The Perl6::Currying module lets you try out the new Perl 6 explicit higher-order function syntax in Perl 5." I guess we know who won that debate :^)

Re: subref with stored argument?
by particle (Vicar) on Jan 10, 2003 at 02:14 UTC