Undefined subroutines &main error in Perl

18.7k Views Asked by At

I am trying to extract a DNA sequence from this FASTA file to a specified length of bases per line, say 40.

> sample dna  (This is a typical fasta header.)
agatggcggcgctgaggggtcttgggggctctaggccggccacctactgg
tttgcagcggagacgacgcatggggcctgcgcaataggagtacgctgcct
gggaggcgtgactagaagcggaagtagttgtgggcgcctttgcaaccgcc
tgggacgccgccgagtggtctgtgcaggttcgcgggtcgctggcgggggt

Using this Perl module (fasta.pm):

package fasta;
use strict;

sub read_fasta ($filename) {
    my $filename = @_;
    open (my $FH_IN, "<", $filename) or die "Can't open file: $filename $!";
    my @lines = <$FH_IN>;
    chomp @lines;
    return @lines;
}

sub read_seq (\@lines) {
    my $linesRef = @_;
    my @lines = @{$linesRef};
    my @seq;
    foreach my $line (@lines) {
        if ($line!~ /^>/) {
            print "$line\n";
            push (@seq, $line);
        }
    }
    return @seq;
}

sub print_seq_40 (\@seq) {
    my $linesRef = @_;
    my @lines = @{$linesRef};
    my $seq;
    foreach my $line (@lines) {
        $seq = $seq.$line;
    }

    my $i= 0;
    my $seq_line;
    while (($i+1)*40 < length ($seq)) {
        my $seq_line = substr ($seq, $i*40, 40);
        print "$seq_line\n";
        $i++;
    }
    $seq_line = substr ($seq, $i*40);
    print "$seq_line\n";
}
1;

And the main script is

use strict;
use warnings;
use fasta;

print "What is your filename: ";
my $filename = <STDIN>;
chomp $filename;

my @lines = read_fasta ($filename);
my @seq = read_seq (\@lines);
print_seq_40 (\@seq);
exit;

This is the error I get

Undefined subroutine &main::read_fasta called at q2.pl line 13, <STDIN> line 1.

Can anyone please enlighten me on which part I did wrong?

3

There are 3 best solutions below

0
On BEST ANSWER

It looks like you're getting nowhere with this.

I think your choice to use a module and subroutines is a little strange, given that you call each subroutine only once and the correspond to very little code indeed.

Both your program and your module need to start with use strict and use warnings, and you cannot use prototypes like that in Perl subroutines. Including a number of other bugs, this is a lot closer to the code that you need.

package Fasta;

use strict;
use warnings;
use 5.010;
use autodie;

use base 'Exporter';

our @EXPORT = qw/ read_fasta read_seq print_seq_40 /;

sub read_fasta {
  my ($filename) = @_;

  open my $fh_in, '<', $filename;
  chomp(my @lines = <$fh_in>);

  @lines;
}

sub read_seq {
  my ($lines_ref) = $_[0];

  grep { not /^>/ } @$lines_ref;
}

sub print_seq_40 {
  my ($lines_ref) = @_;

  print "$_\n" for unpack '(A40)*', join '', @$lines_ref;
}

1;

q2.pl

use strict;
use warnings;

use Fasta qw/ read_fasta read_seq print_seq_40 /;

print "What is your filename: ";
my $filename = <STDIN>;
chomp $filename;

my @lines = read_fasta($filename);
my @seq = read_seq(\@lines);
print_seq_40(\@seq);
8
On

In Perl, if you use fasta;, this does not automatically export all its methods into the namespace of your program. Call fasta::read_fasta instead.

Or: use Exporter to automatically export methods or enable something like use Fasta qw/read_fasta/.

For example:

package Fasta;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw/read_fasta read_seq read_seq40/;

To use:

use Fasta qw/read_fasta read_seq read_seq40/;

You can also make Fasta export all methods automatically or define keywords to group methods, though the latter has caused me some problems in the past, and I would recommend it only if you are certain it is worth possible trouble.

If you want to make all methods available:

package Fasta;
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw/read_fasta read_seq read_seq40/;

Note @EXPORT is not @EXPORT_OK. The latter allows importing them later (as I did), the former automatically exports all. The documentation I linked to makes this clear.

I just noticed something else. You are flattening @_ into $filename in read_fasta. I am not sure this works. Try this:

sub read_fasta {
   my $filename = $_[0]; # or ($filename) = @_; @_ is an array. $filename not.
}

To explain the problem: $filename = @_; means: store @_ ( an ARRAY ) into $filename (a SCALAR). Perl does this in this way: ARRAY length is stored in $filename. That is not what you want. You want the first element of the array. That would be $_[0].

Added @ISA which is probably needed OR use comment by Borodir.

2
On

You need to either:

  • add to your module:

    use Exporter;
    our @EXPORT = qw ( read_fasta
                       read_seq ); #etc.
    
  • call the code in the remote module explicitly:

    fasta::read_fasta();
    
  • explicitly import the module sub:

    use fasta qw ( read_fasta );
    

Also: General convention on modules is to uppercase the first letter of the module name.