Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

make subroutine that takes expression as implicit block as first arg

by myuserid7 (Scribe)
on Aug 13, 2010 at 19:42 UTC ( [id://854993]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, I want to make my own subroutine work like grep() or map(), being able to take either a block or an expression as a first argument; and if an expression is given, automatically put an it in an implicit block, just like grep() and map() does The block part is easy; but is it possible to make it do the expression part? For example, how to define mygrep(), such that I can do
mygrep($_ % 2 == 0, 0..10)
just like I can do
grep($_ % 2 == 0, 0..10)

Replies are listed 'Best First'.
Re: make subroutine that takes expression as implicit block as first arg
by LanX (Saint) on Aug 13, 2010 at 19:56 UTC
    > The block part is easy; but is it possible to make it do the expression part?

    no, unfortunately there's no prototype mechanism for the latter.

    You can neither easily allow calling a function (which is a special case of the expression part).

    There was a discussion about this a year ago, I will update a link.

    UPDATE:

    see coderefs and (&) prototypes and The & prototype and code references in scalars..

    Cheers Rolf

Re: make subroutine that takes expression as implicit block as first arg
by kennethk (Abbot) on Aug 13, 2010 at 19:46 UTC
    You can accomplish your task using Prototypes. In fact, from the linked documentation,
    here's a reimplementation of the Perl grep operator:

    sub mygrep (&@) { my $code = shift; my @result; foreach $_ (@_) { push(@result, $_) if &$code; } @result; }

    Update: Your example would be called as: print join ",", mygrep {$_ % 2 == 0} 0..10; Note the deviation from the proposed use case. I'd initially missed the spec for "automatically put [ting] it in an implicit block"

      That won't work, for the proposed case:

      Type of arg 1 to main::mygrep must be block or sub {} (not numeric eq +(==)) at /tmp/mygrep line 7, near "10)" Execution of /tmp/mygrep aborted due to compilation errors.

      Perhaps something like this?

      sub mygrep { my $s = "grep $_[0]"; eval $s; } print for mygrep('$_ % 2 == 0, 0..10'); # :-)

      --
      "Language shapes the way we think, and determines what we can think about."
      -- B. L. Whorf
        I added a use case, as this sort of structure is a bit sensitive - perl apparently interprets the OP proposed use case as an anonymous hash because parentheses are present.

        When I was going through a clever phase, I played a bit with prototypes, and decided they are generally more trouble than they are worth. IMHO, of course.

Re: make subroutine that takes expression as implicit block as first arg
by JavaFan (Canon) on Aug 14, 2010 at 10:19 UTC
    In pure Perl, this isn't possible. However, 5.12 has pluggable keywords; I wouldn't rule it out it's possible by creating a new keyword. Unfortunally, my knowledge about pluggable keywords doesn't extend further than "I know they exist".

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://854993]
Approved by kennethk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (7)
As of 2024-04-18 15:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found