what is the usage of \& and $expr->() - perl

sub reduce(&#) {
my $expr = \&{shift #ARG};
my $result = shift #ARG;
while (scalar #ARG > 0) {
our $a = $result;
our $b = shift #ARG;
$result = $expr->();
}
return $result;
}
I cannot really understand some grammar in this code. Anyone can explain to me? like \& and $result = $expr->()

\&name returns a reference to the subroutine named name.
$code_ref->() calls the subroutine referenced by $code_ref.
$ perl -e'
sub f { CORE::say "Hi" }
my $code_ref = \&f;
$code_ref->();
'
Hi
In your case, shift #ARG returns a subroutine reference. \&{ $code_ref } simply returns the code ref. As such,
my $expr = \&{shift #ARG};
could have been written as
my $expr = shift #ARG;
Note that reduce's prototype allows it to be called as
reduce { ... } ...
but what is actually executed is
reduce( sub { ... }, ... )
Note that this version of reduce is buggy. You should use the one provided by List::Util.
local $a and local $b should have been used to avoid clobbering the values its caller might have in $a and $b.
This version of reduce expects its callback to have been compiled in the same package as reduce itself. Otherwise, the callback sub won't be able to simply use $a and $b.
Declaring the variables using our is actually completely useless in this version case since $a and $b are exempt from use strict; checks, and the undeclared use of $a and $b would access the very same package variables.

Having a look some List::Util::reduce() examples will probably help.
Let's take the first one:
$foo = reduce { $a > $b ? $a : $b } 1..10;
So reduce takes a BLOCK followed by a LIST, which the function signature declares: sub reduce(&#) {. The block in our case is the statement $a > $b ? $a : $b, while the list is 1..10. From the docs:
Reduces #list by calling "BLOCK" in a scalar context multiple times,
setting $a and $b each time. The first call will be with $a and $b set to
the first two elements of the list, subsequent calls will be done by
setting $a to the result of the previous call and $b to the next element
in the list.
Returns the result of the last call to the "BLOCK". If #list is empty then
"undef" is returned. If #list only contains one element then that element
is returned and "BLOCK" is not executed.
And now to an annotated version of the code:
$foo = reduce { $a > $b ? $a : $b } 1..10; # $foo will be set to 10
sub reduce(&#) {
# reduce() takes a BLOCK followed by a LIST
my $expr = \&{shift #ARG};
# $expr is now a subroutine reference, i.e.
# $expr = sub { $a > $b ? $a : $b };
# Start by setting $result to the first item in the list, 1
my $result = shift #ARG;
# While there are more items in the list...
while (scalar #ARG > 0) {
# Set $a to the current result
our $a = $result;
# Set $b to the next item in the list
our $b = shift #ARG;
# Set $result to the result of $a > $b ? $a : $b
$result = $expr->();
}
# List has now been reduced by the operation $a > $b ? $a : $b
return $result;
}

Related

The statements inside the label executes even if the condition fails.Can anyone explain what I'm doing here wrong?

my $a =10;
my $b =200;
my $c,$d;
goto UP if ($a > 20);
$d = $c + $b;
print "$d\n";
UP:
$c = $b -$a;
print "$c\n";
The above statements inside the label executes even if the condition fails.
It seems like you are mixing up how the labels and goto work. In fact, goto should never be used for flow control. It's really confusing.
This is how your code runs at the moment:
As you can see, the last two statements (those are after your UP label) are always executed. Perl will check the condition, and if it is true, skip ahead. If the condition is false, it runs the two statements following immediately, and then runs the label and the rest.
Labels don't make subroutines in Perl. They just give a line a name. The line of code is still executed normally.
If you want to do one or the other instead, you need an if-else construct. That's done like this in Perl.
my $a = 10;
my $b = 200;
my ( $c, $d );
if ($a > 20) {
$c = $b -$a;
print "$c\n";
} else {
$d = $c + $b;
print "$d\n";
}
Since you seem to insist on goto, you can make that work, but you need to tell it to stop execution.
my $a =10;
my $b =200;
my $c,$d;
goto UP if ($a > 20);
$d = $c + $b;
print "$d\n";
exit; # <------------- this stops execution and ends the program
UP:
$c = $b -$a;
print "$c\n";
Of course your code won't do much, because both $c and $d are undef.
You should really turn on use strict and use warnings, and fix the problems both of these pragmata will show you.
Also note that $a and $b are reserved variables to be used inside sort.
The code you posted is equivalent to the following:[1]
A: my $a = 10;
B: my $b = 200;
C: my ($c, $d);
D: goto G if $a > 20;
E: $d = $a + $b;
F: print "$d\n";
G: $c = $b - $a;
H: print "$c\n";
As this better demonstrates, code execution doesn't stop once a label is encountered.
To emulate an if-then-else structure, you'd use
my $a = 10;
my $b = 200;
$a > 20 and goto ELSE;
my $d = $a + $b;
print "$d\n";
goto END;
ELSE:
my $c = $b - $a;
print "$c\n";
END:
You probably know this, but the following is a lot clearer and provides better scoping:
my $a = 10;
my $b = 200;
if ($a <= 20) {
my $d = $a + $b;
print "$d\n";
} else {
my $c = $b - $a;
print "$c\n";
}
After a couple of off-topic fixes

Concatenate Arrays as String with PowerShell

i have two array ($a , $b) which holds the following strings:
$a
MSSQL11.SQLINST15
MSSQL12.SQLINST16
MSSQL12.SQLINST17
$b
2874
2884
2885
That i'm trying to concatenate to a new array ($c), as a strings with a comma sign in the middle:
$c
MSSQL11.SQLINST15,2874
MSSQL12.SQLINST16,2884
MSSQL12.SQLINST17,2885
Problem is, that using my current ps code:
$c = #($a + ',' + $b)
[string]::Concat($c)
$c
I'm getting a very strange output:
MSSQL11.SQLINST15
MSSQL12.SQLINST16
MSSQL12.SQLINST17
,
2887
2884
2885
At the end, i've use a powershell hashtable.
I like this way of doing it. Create a zip function to combine your two arrays into a single array of tuples.
Then it's just a matter of piping piece-wise over that tuple list our zip function gives us. Super convenient and reusable.
function Zip($a, $b) {
while ($a) {
$x, $a = $a
$y, $b = $b
[tuple]::Create($x, $y)
}
}
$c = zip $a $b |% {$_.item1 + [string]$_.item2}
Note you can choose where ya wanna to your [string] conversion (in the following, the last line of zip).
function Zip($a, $b) {
while ($a) {
$x, $a = $a
$y, $b = $b
[tuple]::Create([string]$x, $y)
}
}
$c = zip $a $b |% {$_.item1 + $_.item2}
Extra info: Looks like you're accidentally just combining the two arrays using a ",". But $a and $b are arrays, so what you actually want to do is combine the first element of $a with the first element of $b (aka $a[0] + [string]$b[0], and so on for each element. Why the [0]? Remember we almost always start counting at 0 in programming. So the second item of an array is actually [1].
Edit: Here is an example using a foreach loop.
```
foreach($item in $a) {
$i = $a.IndexOf($item)
$a[$i] + [string]$b[$i]
}
```
If for some reason $a has 10 things in it, and $b only has 2 things, it's gonna give you funny behavior. So be careful there. Please let me know if I can better clarify anything. Don't forget to experiment.

Perl: Change in Subroutine not printing outside of routine

So I want to change numbers that I pass into a subroutine, and then retain those numbers being changed, but it doesn't seem to work.
my $A = 0;
my $T = 0;
my $C = 0;
my $G = 0;
foreach my $bases in (keys %basereads){
count ($bases, $A, $T, $C, $G);
}
Here is my subroutine
sub count {
my $bases = shift;
my $A = shift;
my $T = shift;
my $C = shift;
my $G = shift;
for (my $i = 0; $i < length($bases); $i++){
print "$bases\t";
if (uc(substr($bases,$i,1)) eq 'A'){
$A++;
}elsif (uc(substr($bases,$i,1)) eq 'T'){
$T++;
} elsif (uc(substr($bases,$i,1)) eq 'G'){
$G++;
} elsif (uc(substr($bases,$i,1)) eq 'C'){
$C++;
} else { next; }
}
print "$A\t$C\t$T\t$G\n";
return my($bases, $A, $T, $C, $G);
}
after the subroutine, I want to stored the altered A, C, T, G into a hashmap. When I print bases and ATCG inside the subroutine, it prints, so I know the computer is running through the subroutine, but it's not saving it, and when I try to manipulate it outside the subroutine (after I've called it), it starts from zero (what I had defined the four bases as before). I'm new to Perl, so I'm a little weary of subroutines.
Could someone help?
Always include use strict; and use warnings; at the top of EVERY script.
With warnings enabled, you should've gotten the following messages:
"my" variable $bases masks earlier declaration in same scope at script.pl line ...
"my" variable $A masks earlier declaration in same scope at script.pl line ...
"my" variable $T masks earlier declaration in same scope at script.pl line ...
"my" variable $C masks earlier declaration in same scope at script.pl line ...
"my" variable $G masks earlier declaration in same scope at script.pl line ...
These are caused by the my before your return statement:
return my($bases, $A, $T, $C, $G);
Correct this by simply removing the my:
return ($bases, $A, $T, $C, $G);
And then you just need to capture your returned values
($bases, $A, $T, $C, $G) = count($bases, $A, $T, $C, $G);
Given that you're new to perl, I'm sure you won't be surprised that your code could be cleaned up further though. If one uses a hash, it makes it a lot easier to count various characters in a string, as demonstrated below:
use strict;
use warnings;
my $A = 0;
my $T = 0;
my $C = 0;
my $G = 0;
foreach my $bases (keys %basereads) {
my %counts;
for my $char (split //, $bases) {
$counts{$char}++;
}
$A += $counts{A};
$T += $counts{T};
$C += $counts{C};
$G += $counts{G};
}

Can I pass arguments to the compare subroutine of sort in Perl?

I'm using sort with a customized comparison subroutine I've written:
sub special_compare {
# calc something using $a and $b
# return value
}
my #sorted = sort special_compare #list;
I know it's best use $a and $b which are automatically set, but sometimes I'd like my special_compare to get more arguments, i.e.:
sub special_compare {
my ($a, $b, #more) = #_; # or maybe 'my #more = #_;' ?
# calc something using $a, $b and #more
# return value
}
How can I do that?
Use the sort BLOCK LIST syntax, see perldoc -f sort.
If you have written the above special_compare sub, you can do, for instance:
my #sorted = sort { special_compare($a, $b, #more) } #list;
You can use closure in place of the sort subroutine:
my #more;
my $sub = sub {
# calc something using $a, $b and #more
};
my #sorted = sort $sub #list;
If you want to pass the elements to be compared in #_, set subroutine's prototype to ($$). Note: this is slower than unprototyped subroutine.

Is there a Perl idiom which is the functional equivalent of calling a subroutine from within the substitution operator?

Perl allows ...
$a = "fee";
$result = 1 + f($a) ; # invokes f with the argument $a
but disallows, or rather doesn't do what I want ...
s/((fee)|(fie)|(foe)|(foo))/f($1)/ ; # does not invoke f with the argument $1
The desired-end-result is a way to effect a substitution geared off what the regex matched.
Do I have to write
sub lala {
my $haha = shift;
return $haha . $haha;
}
my $a = "the giant says foe" ;
$a =~ m/((fee)|(fie)|(foe)|(foo))/;
my $result = lala($1);
$a =~ s/$1/$result/;
print "$a\n";
See perldoc perlop. You need to specify the e modifier so that the replacement part is evaluated.
#!/usr/bin/perl
use strict; use warnings;
my $x = "the giant says foe" ;
$x =~ s/(f(?:ee|ie|o[eo]))/lala($1)/e;
print "$x\n";
sub lala {
my ($haha) = #_;
return "$haha$haha";
}
Output:
C:\Temp> r
the giant says foefoe
Incidentally, avoid using $a and $b outside of sort blocks as they are special package scoped variables special-cased for strict.