#perl #scoping
#perl #определение области видимости
Вопрос:
Будучи студентом-биологом, я пытаюсь расширить свои знания в области программирования, и я столкнулся с проблемой с Perl.
Я пытаюсь создать программу, которая генерирует случайные строки ДНК и выполняет анализ сгенерированных данных.
В первой части программы я могу распечатать строки, хранящиеся в массиве, но во второй части я не могу получить все элементы массива, кроме одного.
Может ли это быть частью правил определения области видимости в 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;
Комментарии:
1. оберните логику в функции. простой код — это часть ***, которую вы знаете. комментарии могли бы помочь, но, пожалуйста, прочитайте о функциях. кроме того, правила именования плохие. вы должны использовать s_n_a_k_e или cAmEl case.
2. Вы не ограничиваете свои переменные.
3. Любые необъявленные переменные являются глобальными, включая любые опечатки. Это неудачное значение по умолчанию в Perl. Включите
use strict
иuse warnings
, а затем выполните процесс определения области видимости всех этих переменных. Это тяжело, но если ты не сделаешь этого сейчас, будет только хуже.4. Возможно, вы сможете использовать Algorithm::Diff
Ответ №1:
Это не проблема области видимости. Вы не объявили ни одну из своих переменных, что неявно делает их глобальными и доступными везде в вашем коде
Я переформатировал вашу программу на Perl, чтобы иметь возможность читать ее, а затем добавил это в начало вашей программы
use strict;
use warnings 'all';
которые необходимы в каждой написанной вами программе на Perl
Затем я добавил
no strict 'vars';
что является очень плохой идеей и позволяет вам уйти без объявления каких-либо переменных
Результат таков
Argument "ii" isn't numeric in array element at E:Perlsourcedna.pl line 60.
Argument "ii" isn't numeric in array element at E:Perlsourcedna.pl line 61.
Argument "ii" isn't numeric in array element at E:Perlsourcedna.pl line 67.
Argument "j" isn't numeric in array element at E:Perlsourcedna.pl line 42.
Bareword "ii" not allowed while "strict subs" in use at E:Perlsourcedna.pl line 60.
Bareword "ii" not allowed while "strict subs" in use at E:Perlsourcedna.pl line 61.
Bareword "ii" not allowed while "strict subs" in use at E:Perlsourcedna.pl line 67.
Bareword "j" not allowed while "strict subs" in use at E:Perlsourcedna.pl line 42.
Execution of E:Perlsourcedna.pl aborted due to compilation errors.
Строка 42 (моей переформатированной версии)
$largearray[j] = $dnastring
и строки 60, 61 и 67 являются
$line = $largearray[ii];
print $largearray[ii]; #CANNOT RETRIEVE ARRAY VALUES
и
$line = $largearray[ii];
Вы используете j
и ii
в качестве индексов массива. Это вызовы подпрограмм Perl, а не переменные. Добавление use strict
остановило бы компиляцию, если бы вы также не объявили sub ii
и sub j
Вам может сойти с рук, если вы просто измените j
and ii
на $j
and $ii
, но вы наверняка столкнетесь с дальнейшими проблемами
Пожалуйста, внесите те же изменения в свой собственный код и объявите каждую переменную, которая вам нужна, используя my
как можно ближе к первому месту, где они используются
Вам также следует улучшить именование переменных. Такие вещи, как @largearray
бессмысленны: @
говорит, что это массив, и независимо от того, большой он или нет, он относителен и мало полезен для понимания вашего кода. Если у вас нет лучшего описания его назначения, тогда @table
или @data
, вероятно, немного лучше
Аналогично, пожалуйста, избегайте заглавных букв и большинства однобуквенных имен. @V
$Cm
и $Im
бессмысленны, и вам понадобилось бы меньше комментариев, если бы эти имена были лучше
Вам, конечно, не понадобились бы комментарии типа # end while loop
и # outer for loop
, если бы вы правильно расположили свои блоки и сделали их достаточно короткими, чтобы на экране можно было одновременно видеть и начало, и конец, и чем меньше комментариев вы сможете избежать, тем лучше, потому что они сильно загромождают структуру кода
Наконец, стоит отметить, что for
цикл в стиле C редко является лучшим выбором в Perl. Ваш
for ( $i = 1; $i <= $n; $i ) { ... }
намного понятнее, поскольку
for my $i ( 1 .. $n ) { ... }
и объявление управляющей переменной в этот момент делает ненужным придумывать новые имена, например $ii
, для каждого нового цикла
Комментарии:
1. Спасибо вам за все ваши советы. Это моя первая попытка написать что-либо на Perl.
2. @armorlord: Всегда пожалуйста. Но я думаю, что вы взяли на себя слишком много в качестве первой попытки освоить Perl. Самый длинный распространенный алгоритм подпоследовательности, который вы пытаетесь реализовать, сам по себе довольно неудобен, и бороться с этим без досконального знания языка — большая проблема. Вы должны работать через отличные learn.perl.org в котором также есть ссылки на другие полезные ресурсы. Основная документация по Perl находится в режиме онлайн на том же сайте perdoc.perl.org и будет иметь неоценимое значение.
Ответ №2:
Я думаю, что у вас есть опечатка в вашем коде:
ii
=> должно быть $ii
не забудьте поместить это в начале вашего кода:
use strict;
use warnings;
чтобы избежать ошибок такого (и других) типа