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

Hi Monks :),

Once again, I am very new to Perl, so my question is quite basic, perhaps even obvious, but I have spent several hours reading perldoc and am still stumped, so, here goes:

I've just began creating sub routines in exercises, and I'm having a big problem. I'm supposed to write a routine, that takes a number from 1 - 9, and returns the english name of that number, i.e. 1 - "one" , etc. So the program prompts user for number, then sub routine is called. However, it is seriously going wrong :\, this is the code:

#usr/bin/perl use strict; use warnings; my $input; print "Enter a number\n"; chomp($input = <STDIN>); print &number_return ($input); ##sub_routines################################ sub number_return { my $answer = shift(@_); my @numbers = (1,2,3,4,5,6,7,8,9); my @words = ("one","two","three","four","five","six","seven","eight"," +nine"); my $i = 0; my $sum; while ($answer <= 9) { if ($answer eq $numbers[$i]) { $answer = $words[$i]; $i++; $answer; } else { #print $answer; } # end if } # end while } # end sub

First of all, the "#print $answer" is commented out, because I can't currently get it to enter the first part, so it then becomes a problem. Secondly, I have read chp 8 of the llama book (1st ed.) several times, and I've also read perlman:perlsub several times as well. I got many hints from the perlsub page, and made many changes which did help, however, I really don't quite understand or even suspect where the problem is, so it's hard for me to get clues unless I see code examples, which are quite hard to find on things this basic aside from the llama book, and sometimes Randal uses so many fancy short cuts, he eludes me ( please don't mis-understand, all hail Randal..just commenting on my inability, not his ).

So, in the output, I get several errors, one, when the "else" is not commented out, it reprints the number I typed like 5 million times, second, when it is, it does nothing, I type in a number, and it just sits there. I've read alot about passing parameters, and I'm pretty sure, I did that correctly..? I also tried to use "return" and that ended the routine to soon, so, I stopped that, I've been working on this darn thing since this morning, and although I've made quite a bit of progress since, I just can't think of what else to read, cus I'm not sure where the problem is..?

Anyway, sorry Monks, I know this is very trivial compared to most of the problems here, but I just need a point in the right direction, not someone to do it, just a bit of a push, I guess. Also, I know it isn't the most efficient type of coding, and probably a useless function, but the point is to learn how to write a useful subroutine and I'm entirely frustrated at this point.

Thanks Monks, :) UPDATE!!::

OK, Monks. This was a huge lesson for me as a rookie. So, I took into consideration all of the replies, namely, about using a hash (jwkrahn), and asking myself the questions Perlbotics provided,( however, each reply brought a new insight ), anyway, so I started again, and again became so frustrated, I thought I might SCREAM! Then, all of a sudden, as I stared at the comp cock-eyed, I saw it:

#!usr/bin/perl my %numbers = qw( 0 zero 1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 eight 9 nine ); my $input; my $key; print "Enter your number\n"; chomp ($input = <STDIN>); print $numbers{$input} . "\n";

Yes, three lines of code...I had almost destroyed my computer, over something I easily did in about 2 minutes. My thinking was way too uptight. I was so focused on writing code, I barely thought about the problem and it's simplicity. My approach was wrong, and when I really thought about it ( thanks Perlbotics ;) I saw my structure was way off. So, lesson learned, and in front of the entire Perl community, nonetheless. :) So, as I said, I have learned to slow down, think it through, and see the PROBLEM before the code. I thank you PerlMonks for being there through this epiphany in my young Perl life :)

Replies are listed 'Best First'.
Re: Sub Routine Malfunction
by Perlbotics (Archbishop) on Aug 28, 2008 at 23:59 UTC

    Hi, my first advice would be: take a break (honestly). You describe the symptoms of code blindness.

    Then, you should listen to what use strict; use warnings; is telling you: Useless use of private variable in void context at yourfile.pl line 30. - that's a starting point. Maybe something is missing there? If your loop does not finish (runs 5 million times), then maybe the end-condition is not met? Why? Is it the condition itself? Is it something with the loop variable? What is the concrete name of the loop variable? Where is it modified? Is it modified during each iteration of the loop?

    I hope, that answering theses questions gives you enough of a push - as requested.

    Update/comment: By setting $i=0; you already proved you know array indices start at 0. That is not the problem here...

Re: Sub Routine Malfunction
by jwkrahn (Abbot) on Aug 28, 2008 at 23:52 UTC

    Your problem is that $i is only changed if $answer eq $numbers[$i]. You need to increment $i all the time. Or better, use a hash:

    #usr/bin/perl use strict; use warnings; my %numbers = qw( 0 zero 1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 eight 9 nine ); print "Enter a number\n"; chomp( my $input = <STDIN> ); print $numbers{ $input } if exists $numbers{ $input };
Re: Sub Routine Malfunction
by betterworld (Curate) on Aug 28, 2008 at 23:41 UTC
    while ($answer <= 9) { if ($answer eq $numbers[$i]) { $answer = $words[$i]; $i++; $answer; } else { #print $answer; } # end if } # end while

    Well, $answer here is a word like "eight", and the problem with the loop condition is that you cannot numerically compare "eight" to 9.

    OK, let me give you a hint: When the user inputs 8, you want to print $words[7], don't you? Notice that 7 is 8-1? ;)

Re: Sub Routine Malfunction
by ikegami (Patriarch) on Aug 28, 2008 at 23:47 UTC

    Two tips that should help a lot.

    $answer is used to hold the input, the loop counter and the result? yow! Start by using separate variables for these things.

    Consider using for instead of while, since you're looping over the indexes of an array. Actually, consider using the input as an index into the array and eliminating the loop altogether.

Re: Sub Routine Malfunction
by oko1 (Deacon) on Aug 29, 2008 at 03:20 UTC

    Minor but important note: the shebang at the top of your script needs to be

    #!/usr/bin/perl

    instead of the '#usr/bin/perl' or '#!usr/bin/perl' as you have it in the above scripts. Your version will work in, say, Windows (which ignores the shebang, although it honors any switches present on the shebang line), but would fail on a Unix box.

    
    -- 
    Human history becomes more and more a race between education and catastrophe. -- HG Wells
    
      Yes, the second one had it correctly, the first was a mistake, I'm on linux. Thanks for the input, though..it's always good to know the details you've missed :)
Re: Sub Routine Malfunction
by llancet (Friar) on Aug 29, 2008 at 08:49 UTC
    All above are still too complicated. Even a hash is not needed. What you need is just this:
    #!/usr/bin/perl my @list=(qw/zero one two three four five six seven eight nine/); print "give the input:"; my $in=<STDIN>; print "$list[$in]\n";
    As perl can automatically transform string to integer.
      You have a problem if $in is 75, -8, or Platypus.

      Defensive programming is good programming!
      Wow++, very nice ;) I learn something new with every reply, or rather, I guess, a new way of approaching the problem. I appreciate that, from all of the Monks, because it broadens not just my knowledge, but my perspective, which enables me to begin to design my programs more efficiently. Anyone can study a bit and write some code, it's being able to design the structure of it to do what is needed well, not just to do what is needed, that begins to breed a truly talented programmer . Thank you so much for furthering my ability to learn how to do just that :)
Re: Sub Routine Malfunction
by broomduster (Priest) on Aug 28, 2008 at 23:54 UTC
    When you first enter your while loop, $answer is a number, but you (almost) immediately covert it to a word, so successive comparisons of $answer and 9 are probably not doing what you expect. :-)

    Also, remember that array indices in Perl start at.... 0. On second look, the indexing looks OK. But tracking parallel arrays can get hairy when they need to be updated. jwkrahn's suggestion to use a hash avoids that problem.

Re: Sub Routine Malfunction
by zentara (Cardinal) on Aug 29, 2008 at 15:03 UTC
    Ahh..... the first time you realize the value and usage of hashes........ I still remember my first time. It's sort of like your "Perl brain" shifts from 1rst to 2nd gear.....vroooom.

    I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: Sub Routine Malfunction
by FunkyMonk (Bishop) on Aug 29, 2008 at 21:57 UTC
    Expanding on what Perlbotics had to say, perl's error messages are very helpfull once you have some experience of them. Until you reach that point in your Perl development, the diagnostics pragma can help you understand exactly what perl is complaining about.

    It's easy to use, just start all your programs with

    use strict; use warnings; use diagnostics;

    Normally, I remove my .sig when I don't think it's relevant, but for this post I'll leave it alone.


    Unless I state otherwise, all my code runs with strict and warnings
Re: Sub Routine Malfunction
by gone2015 (Deacon) on Aug 29, 2008 at 15:53 UTC

    OK, so the hash is the most general approach -- and as brother/sister zentara remarks, once you see how many things you can do with them, you wonder how you ever coped without.

    In this special case, as brother/sister llancet points out, you could simply use an array, because Perl treats strings which contain digits as numbers (and vice versa).

    So much for the wonderous ways of Perl.

    From a general programming perspective however, you should worry whether the inputs are valid, especially where a human is involved, as brother/sister apl points out. So your conversion subroutine, whatever its mechanics, ought to check that its input is something it can cope with, and your program needs to be arranged to deal with out of spec input.

    I just wanted to stress that, while the coding issues are interesting -- and Perl has its own little ways -- the art of programming is more than coding.