armorlord armorlord - 1 month ago 17
Perl Question

Scoping in Perl

As a biology student, I'm trying to extend my programming knowledge and I ran into a problem with Perl.

I'm trying to create a program that generates random DNA strings and performs analysis work on the generated data.

In the first part of the program, I am able to print out the strings stored in the array, but the second part I cannot retrieve all but one of the elements of the array.

Could this be part of the scoping rules of Perl?

#!usr/bin/perl

# generate a random DNA strings and print it to file specified by the user.

$largearray[0] = 0;

print "How many nucleotides for the string?\n";
$n = <>;
$mylong = $n;

print "how many strings?\n";
$numstrings = <>;

# @largearray =();
$j = 0;

while ( $j < $numstrings ) {

$numstring = ''; # start with the empty string;
$dnastring = '';
$i = 0;

while ( $i < $n ) {

$numstring = int( rand( 4 ) ) . $numstring; # generate a new random integer
# between 0 and 3, and concatenate
# it with the existing $numstring,
# assigning the result to $numstring.
$i++; # increase the value of $i by one.
}

$dnastring = $numstring;
$dnastring =~ tr/0123/actg/; # translate the numbers to DNA characters.
#print $dnastring;
#print "\n";

$largearray[j] = $dnastring; #append generated string to end of array

#print $largearray[j];
#print $j;
#IN HERE THERE ARE GOOD ARRAY VALUES
#print "\n";

$j++;
}

# ii will be used to continuously take the next couple of strings from largearray
# for LCS matching.

$mytotal = 0;
$ii = 0;

while ( $ii < $numstrings ) {

$line = $largearray[ii];
print $largearray[ii]; #CANNOT RETRIEVE ARRAY VALUES
print "\n";

$ii++;
@string1 = split( //, $line );

$line = $largearray[ii];

#print $largearray[ii];
#print "\n";
$ii++;
chomp $line;
@string2 = split( //, $line );

$n = @string1; #assigning a list to a scalar just assigns the
#number of elements in the list to the scalar.
$m = @string2;

$v = 1;
$Cm = 0;
$Im = 0;

$V[0][0] = 0; # Assign the 0,0 entry of the V matrix

for ( $i = 1; $i <= $n; $i++ ) { # Assign the column 0 values and print
# String 1 See section 5.2 of Johnson
# for loops
$V[$i][0] = -$Im * $i;

}

for ( $j = 1; $j <= $m; $j++ ) { # Assign the row 0 values and print String 2
$V[0][$j] = -$Im * $j;

}

for ( $i = 1; $i <= $n; $i++ ) { # follow the recurrences to fill in the V matrix.
for ( $j = 1; $j <= $m; $j++ ) {

# print OUT "$string1[$i-1], $string2[$j-1]\n"; # This is here for debugging purposes.

if ( $string1[ $i - 1 ] eq $string2[ $j - 1 ] ) {
$t = 1 * $v;
}
else {
$t = -1 * $Cm;
}

$max = $V[ $i - 1 ][ $j - 1 ] + $t;

# print OUT "For $i, $j, t is $t \n"; # Another debugging line.
if ( $max < $V[$i][ $j - 1 ] - 1 * $Im ) {
$max = $V[$i][ $j - 1 ] - 1 * $Im;
}

if ( $V[ $i - 1 ][$j] - 1 * $Im > $max ) {
$max = $V[ $i - 1 ][$j] - 1 * $Im;
}

$V[$i][$j] = $max;
}
} #outer for loop

print $V[$n][$m];
$mytotal += $V[$n][$m]; # append current result to the grand total
print "\n";

} # end while loop

print "the average LCS value for length ", $mylong, " strings is: ";
print $mytotal/ $numstrings;

Answer

I reformatted your Perl program so that I could read it, and then added this to the top of your program

use strict;
use warnings 'all';

which are essential in every Perl program you write

Then I added

no strict 'vars';

which is a very bad idea, and lets you get away without declaring any variables

The result is this

Argument "ii" isn't numeric in array element at E:\Perl\source\dna.pl line 60.
Argument "ii" isn't numeric in array element at E:\Perl\source\dna.pl line 61.
Argument "ii" isn't numeric in array element at E:\Perl\source\dna.pl line 67.
Argument "j" isn't numeric in array element at E:\Perl\source\dna.pl line 42.
Bareword "ii" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 60.
Bareword "ii" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 61.
Bareword "ii" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 67.
Bareword "j" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 42.
Execution of E:\Perl\source\dna.pl aborted due to compilation errors.

Line 42 (of my reformatted version) is

$largearray[j] = $dnastring

and lines 60, 61 and 67 are

$line = $largearray[ii];
print $largearray[ii];    #CANNOT RETRIEVE ARRAY VALUES

and

$line = $largearray[ii];

You are using j and ii as array indexes. Those are Perl subroutine calls, not variables.

You might get away with it if you just change j and ii to $j and $ii, but you are certain to get into further problems

Please make the same changes to your own code, and declare every variable that you need using my as close as possible to the first place they are used

You should also improve your variable naming. Things like @largearray are pointless: the @ says that it's an array, and whether it's large or not is relative, and of little use in understanding your code

Likewise, please avoid capital letters and most single-letter names. @V, $Cm and $Im are meaningless, and you would need few comments if any if those names were better

You certainly wouldn't need comments like # end while loop and # outer for loop if you had indented your blocks properly and kept them short enough so that both the beginning and the end can be seen on the screen at the same time, and the fewer comments you can get away with the better, because they badly clutter the code structure

Comments