Lisp's "some" and "every" functions

Discussion in 'Perl Misc' started by J. Romano, Nov 13, 2004.

  1. J. Romano

    J. Romano Guest

    Dear Perl community,

    Recently I've been learning some Lisp on my own, and I've come
    across two Lisp functions that I wish Perl had: "some" and "every".

    They work somewhat like "grep" and "map" in that they operate on a
    list given a function, but they return only a boolean value.

    For example, in Lisp, to find out if at least one number in a list
    is an odd number, you could write:

    (some #'oddp '(1 2 3 4 5))

    or even:

    (some (lambda (x) (= 1 (mod x 2))) '(1 2 3 4 5))

    In Perl, you COULD write:

    if ( grep { $_ % 2 == 1 } (1, 2, 3, 4, 5) )
    {
    print "An odd number exists in the given list.\n";
    }

    but according to 'perldoc -q "element is contained"', use of "grep" is
    undesirable (especially on large lists) because "grep" checks every
    element even if the first matches.

    As for the "every" function, you can use it to find out if every
    element passes a certain test. For example, in Lisp you could use it
    like this to see if every element in a list is an even number:

    (every #'evenp '(2 4 5 6 8))

    or even:

    (every (lambda (x) (= 0 (mod x 2))) '(2 4 5 6 8))

    In Perl, you COULD write:

    my @list = (2, 4, 5, 6, 8);

    if ( @list == grep { $_ % 2 == 0 } @list )
    {
    print "All number in given list are even.\n";
    }

    but, of course, this suffers from the same inefficiency as the
    previous Perl example.

    This inefficiency is not worth worrying about if the list to
    examine has only a few elements, but if it has a large number of
    elements (or the number of elements is arbitrary), there exist a few
    work-arounds.

    One work-around is mentioned in 'perldoc -q "element is
    contained"', so I won't discuss it here. Another work-around is to
    create a module that defines the "some" and "every" functions to be
    used similarly to how Perl's "grep" and "map" functions are called.
    I've written the code, and here it is (more discussion follows):


    use strict;
    use warnings;

    sub some (&@)
    {
    my $sub = shift(@_);

    foreach (@_)
    {
    return 1 if &$sub;
    }

    return 0;
    }

    sub every (&@)
    {
    my $sub = shift(@_);

    foreach (@_)
    {
    return 0 if not &$sub;
    }

    return 1;
    }

    1;

    __END__


    Now, when this module is "use"d, you can now check for the
    existence of an odd number with the "some" function like:

    my @list = (2, 4, 5, 6, 8);

    if ( some { $_ % 2 == 1 } @list )
    {
    print "An odd number exists in the given list.\n";
    }

    You can also verify that all the numbers in a list are even numbers
    with the "every" function like:

    my @list = (2, 4, 5, 6, 8);

    if ( every { $_ % 2 == 0 } @list )
    {
    print "All number in given list are even.\n";
    }

    These functions don't suffer then same inefficiency discussed in
    the perldoc because they will stop examining the list once the "some"
    function verifies the answer is true, or the "every" function verifies
    that the answer is false.

    A few things to note:

    * The "some" function always returns false on an empty list.
    (because no element exists that passes the test).
    * The "every" function always returns true on an empty list
    (because no element exists that fails the test).
    * These functions always return a true or false (boolean) value.
    They DO NOT return a list, like "map" and "grep" do.
    * These functions must be specified with a block of code.
    In other words, where "grep" can be used like this:
    grep m/^a/i, @list
    or like this:
    grep { m/^a/i } @list
    the "some" and "every" functions can only be used like this:
    some { m/^a/i } @list
    every { m/^a/i } @list


    That's all I have to say on this subject, so Happy Perling!

    -- Jean-Luc Romano
     
    J. Romano, Nov 13, 2004
    #1
    1. Advertising

  2. J. Romano wrote:
    > Dear Perl community,
    >
    > Recently I've been learning some Lisp on my own, and I've come
    > across two Lisp functions that I wish Perl had: "some" and "every".
    >
    > They work somewhat like "grep" and "map" in that they operate on a
    > list given a function, but they return only a boolean value.
    >
    > One work-around is mentioned in 'perldoc -q "element is
    > contained"', so I won't discuss it here. Another work-around is to
    > create a module that defines the "some" and "every" functions to be
    > used similarly to how Perl's "grep" and "map" functions are called.
    > I've written the code, and here it is (more discussion follows):
    >


    The other work-around would be to use List::Any.
    http://search.cpan.org/~vparseval/List-Any-0.03/lib/List/Any.pm

    Rhesa
     
    Rhesa Rozendaal, Nov 13, 2004
    #2
    1. Advertising

  3. Rhesa Rozendaal wrote:
    > J. Romano wrote:
    >
    >> Dear Perl community,
    >>
    >> Recently I've been learning some Lisp on my own, and I've come
    >> across two Lisp functions that I wish Perl had: "some" and "every".
    >>
    >> They work somewhat like "grep" and "map" in that they operate on a
    >> list given a function, but they return only a boolean value.

    >
    > >

    >
    >> One work-around is mentioned in 'perldoc -q "element is
    >> contained"', so I won't discuss it here. Another work-around is to
    >> create a module that defines the "some" and "every" functions to be
    >> used similarly to how Perl's "grep" and "map" functions are called.
    >> I've written the code, and here it is (more discussion follows):
    >>

    >
    > The other work-around would be to use List::Any.
    > http://search.cpan.org/~vparseval/List-Any-0.03/lib/List/Any.pm
    >
    > Rhesa


    It seems Tassilo merged the code of List::Any into List::MoreUtils.
     
    Rhesa Rozendaal, Nov 13, 2004
    #3
  4. Also sprach Rhesa Rozendaal:

    > Rhesa Rozendaal wrote:


    >> The other work-around would be to use List::Any.
    >> http://search.cpan.org/~vparseval/List-Any-0.03/lib/List/Any.pm
    >>
    >> Rhesa

    >
    > It seems Tassilo merged the code of List::Any into List::MoreUtils.


    Not so much merged into but renamed to. I was made aware that
    List::MoreUtils would be a better namespace choice. So that means the
    latest release is always at

    http://search.cpan.org/~vparseval/List-MoreUtils/

    Tassilo
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
     
    Tassilo v. Parseval, Nov 13, 2004
    #4
  5. Tassilo v. Parseval wrote:

    > Also sprach Rhesa Rozendaal:
    >
    >
    >>Rhesa Rozendaal wrote:

    >
    >
    >>>The other work-around would be to use List::Any.
    >>>http://search.cpan.org/~vparseval/List-Any-0.03/lib/List/Any.pm
    >>>
    >>>Rhesa

    >>
    >>It seems Tassilo merged the code of List::Any into List::MoreUtils.

    >
    >
    > Not so much merged into but renamed to. I was made aware that
    > List::MoreUtils would be a better namespace choice. So that means the
    > latest release is always at
    >
    > http://search.cpan.org/~vparseval/List-MoreUtils/
    >
    > Tassilo


    Any chance the old apply() function could find a home there?


    =item apply BLOCK LIST

    Similar to C<map> in that it evaluates BLOCK setting C<$_> to each
    element of LIST in turn. C<apply> returns a list made up of the
    values of C<$_> after BLOCK has been evaluated. In a scalar context
    the last element is returned. Unlike C<map> and C<grep> the elements
    of LIST are not altered.

    @foo = apply { s/\s+/ /g } @bar; # canonicalise whitespace

    This function is nothing more than syntactic sugar for people who find
    the following syntax unpalatable.

    for (@foo = @bar) { s/\s+/ /g }

    =cut

    sub apply (&@) {
    my $action = shift;
    &$action for my @values = @_;
    wantarray ? @values : $values[-1];
    }
     
    Brian McCauley, Nov 13, 2004
    #5
  6. Also sprach Brian McCauley:

    > Tassilo v. Parseval wrote:


    >> Not so much merged into but renamed to. I was made aware that
    >> List::MoreUtils would be a better namespace choice. So that means the
    >> latest release is always at
    >>
    >> http://search.cpan.org/~vparseval/List-MoreUtils/
    >>
    >> Tassilo

    >
    > Any chance the old apply() function could find a home there?


    Ah, sure. I'm always looking for more useful list operations.

    > sub apply (&@) {
    > my $action = shift;
    > &$action for my @values = @_;
    > wantarray ? @values : $values[-1];
    > }


    I can use that verbatimly for the pure-Perl implementation. The XS one
    shouldn't be too tricky either. I'll do that tomorrow.

    Tassilo
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
     
    Tassilo v. Parseval, Nov 13, 2004
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ekzept
    Replies:
    0
    Views:
    400
    ekzept
    Aug 10, 2007
  2. =?Utf-8?B?SXJ3YW5zeWFo?=
    Replies:
    4
    Views:
    2,503
    =?Utf-8?B?SXJ3YW5zeWFo?=
    Oct 30, 2007
  3. Xah Lee
    Replies:
    0
    Views:
    356
    Xah Lee
    Feb 12, 2009
  4. nanothermite911fbibustards
    Replies:
    0
    Views:
    404
    nanothermite911fbibustards
    Jun 16, 2010
  5. nanothermite911fbibustards
    Replies:
    0
    Views:
    347
    nanothermite911fbibustards
    Jun 16, 2010
Loading...

Share This Page