Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I only getting a single element from this "for" statement?

Tags:

raku

I am trying to generate FASTQ files containing 10 random sequences with random quality scores. I originally used the following code, which worked fine:

my @seq  = (rand_fa_seq() for ^10);
my @qual = (rand_qual()   for ^10);

@seq.perl.say;
@qual.perl.say;

sub rand_fa_seq
{
    return join("", roll(20,"ACGT".comb));

}

sub rand_qual
{
    return join("", roll(20,"EFGHIJ".comb))
}

However, wanting to simplify it even more, I thought that perhaps I could remove the parentheses from around the right hand statement. When I did so, I only got a single element in @seq and @qual.

my @seq  = rand_fa_seq() for ^10;
my @qual = rand_qual()   for ^10;

@seq.perl.say;
@qual.perl.say;

sub rand_fa_seq
{
    return join("", roll(20,"ACGT".comb));

}

sub rand_qual
{
    return join("", roll(20,"EFGHIJ".comb))
}

Is this a bug or is this the way it should behave? Without the parentheses is this a scalar context? Will the Great List Refactor change this behavior?


Versions of Perl 6 interpreters in which I have seen this behavior:

MoarVM:

perl6 version 2015.03-204-g8578022 built on MoarVM version 2015.03-60-g36d56f7

JVM:

perl6 version 2015.03-305-ga95107d built on JVM java version "1.7.0_79"
OpenJDK Runtime Environment (rhel-2.5.5.1.el7_1-x86_64 u79-b14)
OpenJDK 64-Bit Server VM (build 24.79-b02, mixed mode)

like image 783
Christopher Bottoms Avatar asked Mar 16 '23 00:03

Christopher Bottoms


2 Answers

Statement modifiers are one of the hallmarks of Perl syntax (cf Perl 5's perldoc), and they survived the transition to version 6.

This means your statements are equivalent to

my @seq;
for ^10 { @seq = rand_fa_seq() }

my @qual;
for ^10 { @qual = rand_qual() }

ie you're assigning a fresh value 10 times in a row (and only the last one survives).

Note that this could also be written more succintly as

my @seq  = rand_fa_seq() xx 10;
my @qual = rand_qual() xx 10;

Also note that by default, the last statement in a sub provides the return value.

Assuming you might need sequences of length other than 20, you could parametrize that value, ending up with the following:

sub rand-fa-seq($n = 20) { <A C G T>.roll($n).join }
sub rand-qual($n = 20)   { <E F G H I J>.roll($n).join }

my @seq  = rand-fa-seq() xx 10;
my @qual = rand-qual() xx 10;

where I've used quote words instead of splitting a string.

like image 57
Christoph Avatar answered Apr 30 '23 08:04

Christoph


The second example is like the classical perl5 control statements at the end of the line.

Like

say "true" if something();
say "yeah" for ^10;

if you would put a print statement within rand_qual() you would notice that it's still being executed 10 times.

like image 29
Patrick J. S. Avatar answered Apr 30 '23 08:04

Patrick J. S.