Why does #array ~~ LIST return false even though #array contains the same elements as LIST? - perl

I have
#a = (1,2,3); print (#a ~~ (1,2,3))
and
#a = (1,2,3); print (#a == (1,2,3))
The first one is the one I expect to work, but it does not print anything. The second one does print 1.
Why? Isn't the smart matching operator ~~ supposed to match in the case of #a ~~ (1,2,3)?

For a second, lets consider the slightly different
\#a ~~ (1,2,3)
~~ evaluates its arguments in scalar context, so the above is the same as
scalar(\#a) ~~ scalar(1,2,3)
\#a (in any context) returns a reference to #a.
1, 2, 3 in scalar context is similar to do { 1; 2; 3 }, returning 3.
So minus a couple of warnings*, the above is equivalent to
\#a ~~ 3
What you actually want is
\#a ~~ do { my #temp = (1,2,3); \#temp }
which can be shortened to
\#a ~~ [ 1,2,3 ]
Finally, the magic of ~~ allows \#a to be written as #a, so that can be shortened further to
#a ~~ [ 1,2,3 ]
* — Always use use strict; use warnings;!

Smart match tries to do what I think you're expecting if you use an array or an array reference on the right side -- but not a list.
$ perl -E '#a = (1, 2, 3); say (#a ~~ (1, 2, 3))'
$ perl -E '#a = (1, 2, 3); say ((1, 2, 3) ~~ #a)' # also misguided, but different
1
$ perl -E '#a = (1, 2, 3); say (#a ~~ [1, 2, 3])'
1

Start with What is the difference between a list and an array? in the perlfaq. It specifically shows you how your choice of values is wrong.
You might also start by writing out why you expected each to work or not work, so that we might correct your expectations. Why did you think you'd get the results that you expected?
As for the smart match bits, there's no rule for ARRAY ~~ LIST. The smart match only works with the pairs enumerated in its table in perlsyn. It's going to force it to be one of those pairs.
When you run into these problems, try many more cases:
#!perl
use v5.10.1;
use strict;
use warnings;
my #a = (1,2,3);
say "\#a is #a";
say "\#a ~~ (1,2,3) is ", try( #a ~~ (1,2,3) );
say "\#a ~~ [1,2,3] is ", try( #a ~~ [1,2,3] );
say "\#a ~~ 3 is ", try( #a ~~ 3 );
say "3 ~~ \#a is ", try( 3 ~~ #a );
say '';
my #b = (4,5,6);
say "\#b is #b";
say "\#b ~~ (4,5,6) is ", try( #b ~~ (4,5,6) );
say "\#b ~~ [4,5,6] is ", try( #b ~~ [4,5,6] );
say "\#b ~~ 3 is ", try( #b ~~ 3 );
say "3 ~~ \#b is ", try( 3 ~~ #b );
say '';
say "\#b ~~ \#a is ", try( #b ~~ #a );
sub try { $_[0] || 0 }
The output of the various cases is the clue that you misread the docs:
Useless use of a constant (2) in void context at test.pl line 8.
Useless use of a constant (4) in void context at test.pl line 17.
Useless use of a constant (5) in void context at test.pl line 17.
#a is 1 2 3
#a ~~ (1,2,3) is 0
#a ~~ [1,2,3] is 1
#a ~~ 3 is 0
3 ~~ #a is 1
#b is 4 5 6
#b ~~ (4,5,6) is 0
#b ~~ [4,5,6] is 1
#b ~~ 3 is 0
3 ~~ #b is 0
#b ~~ #a is 0

Related

perl6 Is using junctions in matching possible?

Is it possible to use junction to match any of the values in a junction? I want to match any of the values in an array. What is the proper way to do it?
lisprog$ perl6
To exit type 'exit' or '^D'
> my #a=<a b c>
[a b c]
> any(#a)
any(a, b, c)
> my $x=any(#a)
any(a, b, c)
> my $y = "a 1"
a 1
> say $y ~~ m/ $x /
False
> say $y ~~ m/ "$x" /
False
> my $x = any(#a).Str
any("a", "b", "c")
> say $y ~~ m/ $x /
False
> say $y ~~ m/ || $x /
False
> say $y ~~ m/ || #a /
「a」
>
Thanks !!
Junctions are not meant to be interpolated into regexes. They're meant to be used in normal Perl 6 expressions, particularly with comparison operators (such as eq):
my #a = <x y z>;
say "y" eq any(#a); # any(False, True, False)
say so "y" eq any(#a); # True
To match any of the values of an array in a regex, simply write the name of the array variable (starting with #) in the regex. By default, this is interpreted as an | alternation ("longest match"), but you can also specify it to be a || alternation ("first match"):
my #a = <foo bar barkeep>;
say "barkeeper" ~~ / #a /; # 「barkeep」
say "barkeeper" ~~ / || #a /; # 「bar」

Assignment of multiple array subroutine parameters in Perl doesn't work

I'm confused about perl subroutine parameters in this example
when i use references in subroutine parameters it works:
#a = ( 1, 2 );
#b = ( 5, 8 );
#c = add_vecpair( \#a, \#b );
print "#c\n";
print $a[0];
sub add_vecpair { # assumes both vectors the same length
my ( $x, $y ) = #_; # copy in the array references
my #result;
#$x[0] = 2;
for ( my $i = 0; $i < #$x; $i++ ) {
$result[$i] = $x->[$i] + $y->[$i];
}
return #result;
}
but when i don't use references as parameters like this:
#a = ( 1, 2 );
#b = ( 5, 8 );
#c = add_vecpair( #a, #b );
print "#c\n";
print $a[0];
sub add_vecpair { # assumes both vectors the same length
my ( #x, #y ) = #_; # copy in the array references
my #result;
print #y;
for ( my $i = 0; $i < #x; $i++ ) {
$result[$i] = $x[$i] + $y[$i];
}
return #result;
}
..it doesn't work. When do i need to use references as subroutine parameters?
Short version: The issue is this line:
my (#x, #y) = #_;
Assignments are greedy. #x is treated first, and is given as many values from #_ as it can handle. And as it can handle all of them, it ends up getting all of the contents of #_, and #y get none.
The result is the same as this:
my #x = #_; # Gets all of the arguements
my #y; # Gets nothing, and is therefore declared but uninitialized.
This is why using references is recommended when subroutines take more than one value as arguement, and at least one of those values are arrays or hashes.
Longer version:
#_ is a composite of all of the arguements passed to the subroutine, so the original container doesn't matter. Consider the code snippets below. The first one is yours, the second one does the exact same thing, but more clearly displays what is happening.
#a = (1, 2);
#b = (5, 8);
add_vecpair(#a,#b);
....is the same as:
add_vecpair(1, 2, 5, 8);
To further hilight the problem, hashes get really messy if treated this way:
%a = ('a' => 1,
'b' => 2);
%b = ('c' => 3,
'd' => 4);
somefunction(%a, %b);
...is the same as:
somefunction('a', 1, 'b', 2, 'c', 3, 'd', 4);
When you call Perl subroutines with array or hash parameters, they are flattened out to a single list. Therefore in the second case your two array parameters loose their identities and #_ becomes a single array with the elements of both #a and #b.

why does sort with uniq not work together

I have the following script:
use strict;
use List::MoreUtils qw/uniq/;
use Data::Dumper;
my #x = (3,2);
my #y = (4,3);
print "unique results \n";
print Dumper([uniq(#x,#y)]);
print "sorted unique results\n";
print Dumper([sort uniq(#x,#y)]);
The output is
unique results
$VAR1 = [
3,
2,
4
];
sorted unique results
$VAR1 = [
2,
3,
3,
4
];
So it looks that sort does not work with uniq.
I did not understand why.
I ran the perl script with -MO=Deparse and got
use List::MoreUtils ('uniq');
use Data::Dumper;
use strict 'refs';
my(#x) = (3, 2);
my(#y) = (4, 3);
print "unique results \n";
print Dumper([uniq(#x, #y)]);
print "sorted unique results\n";
print Dumper([(sort uniq #x, #y)]);
My interpretation is that perl decided to remove the parentheses from uniq(#x,#y) and using uniq as a function of sort.
Why did perl decide to do it?
How can i avoid these and similar pitfalls?
Thanks,
David
The sort builtin accepts a subroutine name or block as first argument which is passed two items. It then must return a number which determines the order between the items. These snippets all do the same:
use feature 'say';
my #letters = qw/a c a d b/;
say "== 1 ==";
say for sort #letters;
say "== 2 ==";
say for sort { $a cmp $b } #letters;
say "== 3 ==";
sub func1 { $a cmp $b }
say for sort func1 #letters;
say "== 4 ==";
sub func2 ($$) { $_[0] cmp $_[1] } # special case for $$ prototype
say for sort func2 #letters;
Notice that there isn't any comma between the function name and the list, and note that the parens in Perl are primarly used to determine precedence – sort func1 #letters and sort func1 (#letters) are the same, and neither executes func1(#letters).
To disambiguate, place a + before the function name:
sort +uniq #letters;
To avoid such unexpected behaviour, the best solution is to read the docs when you aren't sure how a certain builtin behaves – unfortunately, many have some special parsing rules.
You could put parenthesis arround the uniq fonction:
print Dumper([sort (uniq(#x,#y))]);
output:
$VAR1 = [
2,
3,
4
];

perl :"//" operator?

I have a question about using "//" operator, my testing code is as following:
perl -e '#arr1=();#arr2=(1,2,3);#arr3=defined(#arr1)?#arr1:#arr2;print "[#arr3]\n"'
[1 2 3]
perl -e '#arr1=();#arr2=(1,2,3);#arr3=#arr1//#arr2;print "[#arr3]\n"'
[0]
perl -e '$v1=();$v2="123";$v3=defined($v1)?$v1:$v2;print "[$v3]\n"'
[123]
perl -e '$v1=();$v2="123";$v3=$v1//$v2;print "[$v3]\n"'
[123]
my question is, why do using "//" operator give the same results as using "defined()? : " on the scalar, but not array(or hash)?
Thanks!!!
Because the leftmost operand of ?:, ||, or && — or this newfanglulated // thingie — is always evaluated in boolean not list context, whereas the other operands inherit the surrounding context.
#a = #b && #c;
means
if (#b) {
#a = #c;
} else {
#a = scalar #b;
}
While
#a = #b || #c;
and also
#a = #b // #c;
both mean
means
if (#b) {
#a = scalar #b;
} else {
#a = #c;
}
The only way to get rid of the scalar in assigning #b to #a is to use ?:
#a = #b ? #b : #c;
which of course means
if (#b) {
#a = #b;
} else {
#a = #c;
}
There is also the property that ?: can be an lvalue:
(#a > #b ? #a : #b) = #c;
which of course means
if (#a > #b) {
#a = #c;
} else {
#b = #c;
}
EDIT
The implementation of #a // #b and its definition differ. Bug submitted. Thanks.
This has more to do with defined than with //. From perldoc -f defined:
Use of defined on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate had ever been allocated. This behavior may disappear in future versions of Perl.
So in your first example, defined(#arr1) is false; in the second, defined(#arr1) is true, and #arr3 contains scalar(#arr1). The difference between // and defined($a) ? $a : $b is noted in perldoc perlop:
Although it has no direct equivalent in C, Perl's // operator is related to its C-style or. In fact, it's exactly the same as ||, except that it tests the left hand side's definedness instead of its truth. Thus, $a // $b is similar to defined($a) || $b (except that it returns the value of $a rather than the value of defined($a)) and yields the same result as defined($a) ? $a : $b (except that the ternary-operator form can be used as a lvalue, while $a // $b cannot). This is very useful for providing default values for variables. If you actually want to test if at least one of $a and $b is defined, use defined($a // $b).
(Emphasis mine.)
So for example:
(defined($a) ? $a : $b) = $c; # This is valid.
($a // $b) = $c; # This is not.

Sort function in Perl

Consider:
use warnings;
my #a = (1, 11, 3, 5, 21, 9, 10);
my #b = sort #a;
print "#b";
Output: 1 10 11 21 3 5 9
Codepad link: http://codepad.org/Fvhcf3eP
I guess the sort function is not taking the array's elements as an integer. That is why the output is not:
1 3 5 9 10 11 21
Is it?
How can I get the above result as output?
The default implementation of Perl's sort function is to sort values as strings. To perform numerical sorting:
my #a = sort {$a <=> $b} #b;
The linked page shows other examples of how to sort case-insensitively, in reverse order (descending), and so on.
You can create explicit subroutines to prevent duplication:
sub byord { $a <=> $b };
...
#a = sort byord #b;
This is functionally equivalent to the first example using an anonymous subroutine.
You are correct. So just tell Perl to treat it as an integer like below.
File foop.pl
use warnings;
my #a = (1, 11, 3, 5, 21, 9, 10);
my #b = sort {$a <=> $b} #a;
print "#b";
Run
perl foop.pl
1 3 5 9 10 11 21
Provide a custom comparison function (comparing numerically):
sort {$a <=> $b} #array;
Here is a numerical sort:
#sorted = sort { $a <=> $b } #not_sorted
#b = sort { $a <=> $b } #a;
Is numerical
Use the spaceship operator: sort { $a <=> $b } #a
Guessing is the wrong approach. If you don't understand sort, look it up: sort
my #b = sort{$a <=> $b} #a;