Определение области видимости в Perl

#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;
 

чтобы избежать ошибок такого (и других) типа