kotoko has asked for the wisdom of the Perl Monks concerning the following question:

Hi I'm trying the use references to functions but can't seem to get it right. I've done:
$a = sub {return @_[0]}; (yes I know....) $b = sub {return @_[0]+1}; .... some code ..... if (something) $i = $a; else $i = $b; &lala ($i); sub lala{ my $i = $_[0]; $res = &{$i}($number) ; #have also tried $res = $i->($number) with the same result }
It gives me a undefined subroutine &main:: called at ... error. Anybody can give me some advice?

Replies are listed 'Best First'.
Re: using reference to subroutine
by Joost (Canon) on Apr 04, 2007 at 18:44 UTC
Re: using reference to subroutine
by shmem (Chancellor) on Apr 04, 2007 at 18:52 UTC

    Why do you make us waste our time verifying and fixing POC code accompanying your question?

    It gives me a undefined subroutine &main:: called at ... error
    That code, as presented, gives me other errors. First
    Scalar found where operator expected at foo.pl line 2, near ")

    because of the "(yes I know....)" comment which isn't a comment. Fixing that,

    syntax error at foo.pl line 4, near "..."

    it chokes on ".... some code .....".

    Please! Either post runnable code, or post something along with it like "this code doesn't run, can you help me fix it?"

    Cleaning up your code to the point where it is at least runnable, I get

    #!/usr/bin/perl -l $a = sub {return @_[0]}; $b = sub {return @_[0]+1}; if (0) { $i = $a; } else { $i = $b; } $number = 10; print &lala ($i); sub lala{ my $i = $_[0]; $res = &{$i}($number) ; #have also tried $res = $i->($number) with the same result } __END__ 11

    which is kinda what I expected, and whithout errors.

    There are major flaws with your code. Use strict, don't use $a and $b and so on. But now I've spent the time I had for that just to make your piece of code runnable - so sorry, others may hint you at those.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Sorry, wrong version, the code I meant to post was:
      #!/usr/bin/perl $fileName = "tmp.txt"; open(CPF, $fileName) or die ("Can't open file ", $fileName); @lines = <CPF>; close (CPF); $index = 0; @allNames; @allSeq; $nbTaxa; $nbGenes; #$lastLine = "start"; $alternatingIter = sub {return $_[0]}; $followedIter = sub {return (($_[0] % 10) - 1) }; $iter; chop $lines[0]; ($nbTaxa,$nbGenes)=split / +/, $lines[0]; print $nbTaxa." ".$nbGenes."\n"; &sorter ($lines[1]); ($first, $second)= split / +/, $lines[2]; if (((length $second) == 0) && ($first =~ /[AGTC]+/)){ $iter = $followedIter; chop ($first); $allSeq[$index]= $allSeq[$index].$first; print "TYPE: just sequence --> "; print "first:".$first."; second:".$second.";\n"; } elsif (((length $second) > 0) && ($first =~ /(\w)+/) && ($second =~ / +[AGTC]+/) ){ $iter = $alternatingIter; $allNames [$index] = $first; chop ($second); $allSeq [$index] = $second; $index++; print "TYPE: name + sequence --> "; print "first:".$first."; second:".$second.";\n"; } foreach $tmp (@lines[3..@lines]){ &sorter ($tmp, $iter); } for ($i = 0; $i <= $index; $i++){ print $allNames[$i]." --> ".$allSeq[$i]."\n"; } sub sorter { my $tmp = $_[0]; my $iter = $_[1]; ($first, $second)= split / +/, $tmp; if (((length $second) == 0) && ($first =~ /[AGTC]+/)){ chop ($first); $allSeq[$iter]= $allSeq[$index].$first; $index++; print "TYPE: just sequence --> "; print "first:".$first."; second:".$second.";\n"; } elsif (((length $second) > 0) && ($first =~ /(\w)+/) && ($second +=~ /[AGTC]+/) ){ $i = &{$iter}($index); # ou $iter->($index); $allNames [$i] = $first; chop ($second); $allSeq [$i] = $second; $index++; print "TYPE: name + sequence --> "; print "first:".$first."; second:".$second.";\n"; } elsif($first eq "\n"){ print "TYPE: do nothing --> "; print "first:".$first."; second:".$second.";\n"; } else{ print "TYPE: you have a problem with the format of file".$file +Name." --> "; print "first:".$first."; second:".$second.";\n"; } print "index: ".$index."\n"; }
      Here is the tmp.txt file you should use as input
      10 705 Cow ATGGCATATCCCATACAACTAGGATTCCAAGATGCAACATCACCAATCATAGAAGAACTA Carp ATGGCACACCCAACGCAACTAGGTTTCAAGGACGCGGCCATACCCGTTATAGAGGAACTT Chicken ATGGCCAACCACTCCCAACTAGGCTTTCAAGACGCCTCATCCCCCATCATAGAAGAGCTC Human ATGGCACATGCAGCGCAAGTAGGTCTACAAGACGCTACTTCCCCTATCATAGAAGAGCTT Loach ATGGCACATCCCACACAATTAGGATTCCAAGACGCGGCCTCACCCGTAATAGAAGAACTT Mouse ATGGCCTACCCATTCCAACTTGGTCTACAAGACGCCACATCCCCTATTATAGAAGAGCTA Rat ATGGCTTACCCATTTCAACTTGGCTTACAAGACGCTACATCACCTATCATAGAAGAACTT Seal ATGGCATACCCCCTACAAATAGGCCTACAAGATGCAACCTCTCCCATTATAGAGGAGTTA Whale ATGGCATATCCATTCCAACTAGGTTTCCAAGATGCAGCATCACCCATCATAGAAGAGCTC Frog ATGGCACACCCATCACAATTAGGTTTTCAAGACGCAGCCTCTCCAATTATAGAAGAATTA CTTCACTTTCATGACCACACGCTAATAATTGTCTTCTTAATTAGCTCATTAGTACTTTAC CTTCACTTCCACGACCACGCATTAATAATTGTGCTCCTAATTAGCACTTTAGTTTTATAT GTTGAATTCCACGACCACGCCCTGATAGTCGCACTAGCAATTTGCAGCTTAGTACTCTAC ATCACCTTTCATGATCACGCCCTCATAATCATTTTCCTTATCTGCTTCCTAGTCCTGTAT CTTCACTTCCATGACCATGCCCTAATAATTGTATTTTTGATTAGCGCCCTAGTACTTTAT ATAAATTTCCATGATCACACACTAATAATTGTTTTCCTAATTAGCTCCTTAGTCCTCTAT ACAAACTTTCATGACCACACCCTAATAATTGTATTCCTCATCAGCTCCCTAGTACTTTAT CTACACTTCCATGACCACACATTAATAATTGTGTTCCTAATTAGCTCATTAGTACTCTAC CTACACTTTCACGATCATACACTAATAATCGTTTTTCTAATTAGCTCTTTAGTTCTCTAC CTTCACTTCCACGACCATACCCTCATAGCCGTTTTTCTTATTAGTACGCTAGTTCTTTAC
        Several problems here. Use warnings and strict!
        Your error is because you are calling 'sorter' on line 26 with only one argument - you are not passing it an '$iter'.
        It is a bad idea to have a local variable and a global of the same name - very confusing ($iter).
        The syntax for calling the ref should be &$iter($index)
        I also spotted that your foreach loop is wrong, use $#lines for the highest index, @lines will go one element beyond the end of the array (it give s the number of elements).
        Probably more errors lurking, but that should do for now.
        update: $allSeq[&$iter()]= $allSeq[$index].$first;I really hate your use of globals in the subroutine, sorry, but it makes the code difficult to figure out. Should your $first and $second in sorter() overwrite the globals?
      I'm sorry if I made waste your time but (as I replied above) it wasn't possible for me to copy&paste the code. Also I thought it was really basic error that didn't require running to sort out since the problem is I don't know very well how to use references to functions.But I thank you for trying to fix it anyway, not everybody would do that. If the actual code is more usefull for you here it is:
      #!/usr/bin/perl $fileName = $ARGV[0]; $windowSize = $ARGV[1]; $windowIncrement = $ARGV[2]; open(CPF, $fileName) or die ("Can't open file ", $fileName); @lines = <CPF>; close (CPF) or warn ("Unable to close ", $fileName); $n = @lines; $index = 0; @allNames; @allSeq; $nbTaxa; $nbGenes; #$lastLine = "start"; $alternatingIter = sub {return $_[0]}; $followedIter = sub {return (($_[0] % 10) - 1) }; $iter; chop $lines[0]; ($nbTaxa,$nbGenes)=split / +/, $lines[0]; &sorter ($lines[1]); if (((length $second) == 0) && ($first =~ /[AGTC]+/)){ $iter = $followedIter; chop ($first); $allSeq[$index]= $allSeq[$index].$first; print "TYPE: just sequence --> "; print "first:".$first."; second:".$second.";\n"; } elsif (((length $second) > 0) && ($first =~ /(\w)+/) && ($second +=~ /[AGTC]+/) ){ $iter = $alternatingIter; $allNames [$index] = $first; chop ($second); $allSeq [$index] = $second; $index++; print "TYPE: name + sequence --> "; print "first:".$first."; second:".$second.";\n"; } foreach $tmp (@lines[3..@lines]){ &sorter ($tmp); } sub sorter { $tmp = $_[0]; ($first, $second)= split / +/, $tmp; if (((length $second) == 0) && ($first =~ /[AGTC]+/)){ chop ($first); $allSeq[$index]= $allSeq[$index].$first; print "TYPE: just sequence --> "; print "first:".$first."; second:".$second.";\n"; } elsif (((length $second) > 0) && ($first =~ /(\w)+/) && ($second +=~ /[AGTC]+/) ){ $allNames [$index] = $first; chop ($second); $allSeq [$index] = $second; $index++; print "TYPE: name + sequence --> "; print "first:".$first."; second:".$second.";\n"; } elsif($first eq "\n"){ print "TYPE: do nothing --> "; print "first:".$first."; second:".$second.";\n"; } else{ print "TYPE: you have a problem with the format of file".$file +Name." --> "; print "first:".$first."; second:".$second.";\n"; } print "index: ".$index."\n"; }
      I've cutted the parts that don't have anything to do with the problem so I'm almost certain it will run. Still, the problem is the same (using the iter reference) as i didn't understand what you fixed.
Re: using reference to subroutine (assume)
by tye (Sage) on Apr 04, 2007 at 18:34 UTC

    Then $i contains the empty string and the code isn't doing what you think it is. Look at the rest of the code more closely. We can't because you didn't include the actual code (just what you thought the code was). (:

    - tye        

      Thanks for the tip on the empty string.Then how should i do to make 1. an anonymous subroutine (is the $a and $b assigments ok for that?)2. Assign the reference of one of the anonymous subroutines to another variable.And 3. use this last variable to call the subroutine and pass arguments.
Re: using reference to subroutine
by perrin (Chancellor) on Apr 04, 2007 at 18:50 UTC
    $a = sub {return @_[0]}; (yes I know....)
    Yes you know? You know that this is an array slice? I think you meant $_[0] there.
      I meant $_[0], the yes I know was for writing stupid code.The error was because I have to hand copy the code from one pc to another because one doesn't have internet.

        I meant $_[0], the yes I know was for writing stupid code.

        The error was because I have to hand copy the code from one pc to another because one doesn't have internet.

        The biggest error being not that of using @_[0] instead of $_[0], which is valid syntax and fundamentally does the right thing, but that of not putting the "yes I know..." part behind a comment sign, which does not.