问题
I'm trying to implement a subroutine that calculates the d-neighbors of an input string. This is apart of an implementation of planted motif search, but my question is much more general. Here is the code:
#subroutine for generating d-neighbors
sub generate_d_neighbors{
# $sequence is the sequence to generate d-neighbors from
# $HD is the Hamming Distance
my ($sequence, $HD) = @_;
for(my $i = 0; $i=$HD; $i++){
my @l = ['A', 'C', 'T', 'G'];
my @t = splice(@l,$sequence[$i]);
#TODO
}
}
The error is occurring at the last line, saying that:
Global symbol "@sequence" requires explicit package name (did you forget to declare "my @sequence"?
It was my understanding that Perl does not take parameters in the form subroutine(param1, param2) like in Java for example, but why is $sequence not being recognized as already having been initialized?
回答1:
There are some problems with your code:
sub generate_d_neighbors{
my ($sequence, $HD) = @_;
for(my $i = 0; $i=$HD; $i++){
my @l = ['A', 'C', 'T', 'G'];
my @t = splice(@l,$sequence[$i]);
}
}
First, let's look at
for(my $i = 0; $i=$HD; $i++){
Assuming $HD is nonzero, this loop will never terminate because the condition will never be false. If you wanted $i to range from 0 to $HD, writing the statement as for my $i (0 .. $HD) would have been better.
Second, you have
my @t = splice(@l,$sequence[$i]);
where you seem to assume there is an array @sequence and you are trying to access its first element. However, $sequence is a reference to an array. Therefore, you should use
$sequence->[$i]
Third (thanks @Ikegami), you have
my @l = ['A', 'C', 'T', 'G'];
in the body of the for-loop. Then @l will contain a single element, a reference to an anonymous array containing the elements 'A', 'C', 'T', and 'G'. Instead, use:
my @l = qw(A C T G);
I am not sure exactly what you want to achieve with splice(@l, $sequence->[$i]), but that can be better written as:
my @t = @l[0 .. ($sequence->[$i] - 1)];
In fact, you could reduce the two assignments to:
my @t = qw(A C T G)[0 .. ($sequence->[$i] - 1)];
回答2:
It looks to me like you want
substring($sequence, 0, 1)
instead of
$sequence[0].
In Perl, strings are first class variables, not a type of array.
Or maybe you want splice(@l, $sequence->[0])?
回答3:
This list-assignment syntax:
my (@sequence, $HD) = @_;
doesn't do what you might want it to do (put the last argument in $HD and the rest in @sequence). The array always takes all the arguments it can, leaving none for whatever comes after it.
Reversing the order can work, for cases where there is only one array:
my ($HD, @sequence) = @_;
and you make the corresponding change in the caller.
To solve the problem more generally, use a reference:
my ($sequence, $HD) = @_;
and call the sub like this:
generate_d_neighbors(\@foo, $bar);
or this:
# Note the brackets, which make an array reference, unlike parentheses
# which would result in a flat list.
generate_d_neighbors([...], 42);
If you use a prototype:
sub generate_d_neighbors (\@$)
then the caller can say
generate_d_neighbors(@foo, $bar);
and the @foo automatically becomes a reference as if it had been\@foo.
If you use any of the reference-based solutions, you must alter the body of the function to use $sequence instead of @sequence, following these rules:
- Change
@sequenceto@$sequence - Change
$#sequenceto$#$sequence - Change
$sequence[...]to$sequence->[...] - Change
@sequence[...]to@$sequence[...](but be sure you really meant to use an array slice... if you're new to perl you probably didn't mean it, and should have used$sequence[...]instead)
来源:https://stackoverflow.com/questions/43545175/what-is-wrong-with-this-perl-subroutine