From: jl_post on 23 Jul 2010 12:00 Hi, I've been reading up on the smart matching operator ('~~') in "perldoc perlsyn", and I have to say I'm a little confused on a certain aspect of it. Say I have an array like: my @a = ('cat', 'dog', 55); If I want to discover if any of its elements contains only digits, I can use the '~~' operator against a regular expression, like this: if ( @a ~~ m/^\d+$/ ) # prints "true" { print "true"; } else { print "false" } In this respect, the smart matching operator behaves like an "any()" function, returning a true value if any element matches. But if I wanted to discover if any of its elements looks like a number with the Scalar::Util::looks_like_number() function in a code reference, like this: use Scalar::Util qw(looks_like_number); if ( @a ~~ sub { looks_like_number($_[0]) } ) # prints "false" { print "true"; } else { print "false" } the smart matching operator will return a false value. In this case, the smart matching operator behaves like an "all()" function, returning a true value only if every element returns true (or there are no elements that return false). So "Array ~~ Regex" returns true in any elements evaluate to true, but "Array ~~ CodeRef" returns true only if all elements evaluate to true. I find this a bit counter-intuitive. Is there any logic behind this behavior? (I'm asking because I find it difficult to remember which one behaves like any() and which one behaves like all(), since the distinction seems arbitrary to me.) I've discovered that if I want "Array ~~ Regex" to behave like an all() function, I can basically rewrite it by wrapping it in a CodeRef, like this: if ( @a ~~ sub { $_[0] =~ m/^\d+$/ } ) # evaluates to false However, if I want "Array ~~ CodeRef" to behave like an any() function, I have to resort to using De Morgan's laws and write it like this: if (not( @a ~~ sub { not looks_like_number($_[0]) } )) # evaluates to true This works, but I find that this makes the code confusing to read (and to maintain). Is there a better way to get "Array ~~ CodeRef" to behave like an any() function? (Without abandoning the '~~' operator, that is.) I'm aware that I can do this: if ( grep { looks_like_number($_) } @a ) # evaluates to true but I know from experience that many seasoned Perl coders are against this approach. I also know of this approach documented in "perldoc List::Util : sub any { looks_like_number($_) && return 1 for @_; 0 } if ( any(@a) ) # evaluates to true but I'd rather not write a new subroutine every time I need the any() behavior. So basically I'm asking two things: 1.) Why does "Array ~~ Regex" act like any() whereas "Array ~~ CodeRef" act like all()? (In other words, why the discrepancy?) and: 2.) Is there a simple/elegant way to get "Array ~~ CodeRef" to behave like an any() function (like "Array ~~ Regex" does)? Thanks in advance for any advice. -- Jean-Luc
From: C.DeRykus on 23 Jul 2010 17:00 On Jul 23, 9:00 am, "jl_p...(a)hotmail.com" <jl_p...(a)hotmail.com> wrote: > Hi, > > I've been reading up on the smart matching operator ('~~') in > "perldoc perlsyn", and I have to say I'm a little confused on a > certain aspect of it. > > Say I have an array like: > > my @a = ('cat', 'dog', 55); > > If I want to discover if any of its elements contains only digits, > I can use the '~~' operator against a regular expression, like this: > > if ( @a ~~ m/^\d+$/ ) # prints "true" > { > print "true"; > } > else > { > print "false" > } > > In this respect, the smart matching operator behaves like an "any()" > function, returning a true value if any element matches. > > But if I wanted to discover if any of its elements looks like a > number with the Scalar::Util::looks_like_number() function in a code > reference, like this: > > use Scalar::Util qw(looks_like_number); > if ( @a ~~ sub { looks_like_number($_[0]) } ) # prints "false" > { > print "true"; > } > else > { > print "false" > } > > the smart matching operator will return a false value. In this case, > the smart matching operator behaves like an "all()" function, > returning a true value only if every element returns true (or there > are no elements that return false). > > So "Array ~~ Regex" returns true in any elements evaluate to true, > but "Array ~~ CodeRef" returns true only if all elements evaluate to > true. > > I find this a bit counter-intuitive. Is there any logic behind > this behavior? (I'm asking because I find it difficult to remember > which one behaves like any() and which one behaves like all(), since > the distinction seems arbitrary to me.) > > I've discovered that if I want "Array ~~ Regex" to behave like an > all() function, I can basically rewrite it by wrapping it in a > CodeRef, like this: > > if ( @a ~~ sub { $_[0] =~ m/^\d+$/ } ) # evaluates to false > > However, if I want "Array ~~ CodeRef" to behave like an any() > function, I have to resort to using De Morgan's laws and write it like > this: > > if (not( @a ~~ sub { not looks_like_number($_[0]) } )) # evaluates > to true > > This works, but I find that this makes the code confusing to read (and > to maintain). > > Is there a better way to get "Array ~~ CodeRef" to behave like an > any() function? (Without abandoning the '~~' operator, that is.) I'm > aware that I can do this: > > if ( grep { looks_like_number($_) } @a ) # evaluates to true > > but I know from experience that many seasoned Perl coders are against > this approach. I also know of this approach documented in "perldoc > List::Util : > > sub any { looks_like_number($_) && return 1 for @_; 0 } > if ( any(@a) ) # evaluates to true > > but I'd rather not write a new subroutine every time I need the any() > behavior. > Wouldn't the short-circuiting List::Util::first or List::MoreUtils::any fit the bill then...? if ( List::Util::first { looks_like_number($_) } @a ) {...} if ( List::MoreUtils::any { looks_like_number($_) } @a {...} > > So basically I'm asking two things: > > 1.) Why does "Array ~~ Regex" act like any() whereas "Array ~~ > CodeRef" act like all()? (In other words, why the discrepancy?) > > and: > > 2.) Is there a simple/elegant way to get "Array ~~ CodeRef" to behave > like an any() function (like "Array ~~ Regex" does)? > Maybe something such as this: use feature 'state'; if ( @a ~~ sub{ state $r; $r //= L::U::first {looks_like_number($_)} @a } ) .... -- Charles DeRykus
From: jl_post on 23 Jul 2010 17:35 > On Jul 23, 9:00 am, "jl_p...(a)hotmail.com" <jl_p...(a)hotmail.com> wrote: > > > but I'd rather not write a new subroutine every time I need the any() > > behavior. On Jul 23, 3:00 pm, "C.DeRykus" <dery...(a)gmail.com> replied: > > Wouldn't the short-circuiting List::Util::first or > List::MoreUtils::any fit the bill then...? > > if ( List::Util::first { looks_like_number($_) } @a ) {...} > > if ( List::MoreUtils::any { looks_like_number($_) } @a {...} Ah, List::MoreUtils is exactly what I'm looking for. Thanks. Unfortunately, List::MoreUtils doesn't seem to be a standard module (at least according to http://perldoc.perl.org/index-modules-L.html). So on platforms where I can only depend on standard modules I suppose I can use List::Util::first() instead, as long as the set of values I'm looking for can never be undefined. (Otherwise, I wouldn't know if I got a proper match, or if no match at all was found.) (So now I know a nice work-around to getting "Array ~~ CodeRef" any() behavior, but I still don't know the reason behind the "Array ~~ Regex" and "Array ~~ CodeRef" any/all discrepancy.) Thanks again for the response, Charles. It was useful. Cheers, -- Jean-Luc
From: Alan Curry on 23 Jul 2010 17:55 In article <a4526931-df5f-4acd-9b48-66e5143f9a09(a)i31g2000yqm.googlegroups.com>, jl_post(a)hotmail.com <jl_post(a)hotmail.com> wrote: > > use Scalar::Util qw(looks_like_number); > if ( @a ~~ sub { looks_like_number($_[0]) } ) # prints "false" > { > print "true"; > } > else > { > print "false" > } > >the smart matching operator will return a false value. In this case, >the smart matching operator behaves like an "all()" function, No it doesn't. Try it with @a=(1,2,3); it's still false. The coderef is only called once, with \@a as the argument. You passed an arrayref to looks_like_number, which is going to be false no matter what. You're right about one thing at least: it's not easy to predict what ~~ will do based on the documentation. -- Alan Curry
From: Ilya Zakharevich on 24 Jul 2010 02:38 On 2010-07-23, jl_post(a)hotmail.com <jl_post(a)hotmail.com> wrote: > I find this a bit counter-intuitive. There is nothing "a bit counter-intuitive" about the smart matching operation. It is just *absolutely useless*, since there is no humanly-possible way to predict what it would do. The only way to handle the situation is to ignore this operator completely, and black-list as unmaintainable any code which uses it. Hope this helps, Ilya
|
Next
|
Last
Pages: 1 2 3 Prev: FAQ 8.16 How can I sleep() or alarm() for under a second? Next: exist function in perl 5.12.1 |