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?
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)];
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])
?
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
@sequence
to @$sequence
- Change
$#sequence
to $#$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)