By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,852 Members | 1,410 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,852 IT Pros & Developers. It's quick & easy.

Error when using coderefs.

P: 4
Hello,

I am trying some code from Higher Order Perl by Mark Jason Dominus and it doesn't work. When I tried to replace the original print statements with a reference to a subroutine (print_instruction) that prints, I kept getting the error message "Undefined subroutine &main:: called at hanoi.pl line 27." Line 27 is marked in the code below in a comment (it shows as line 21 in the posting below). It doesn't like the dereferencing of the subroutine reference I passed in. This was cut and pasted from his website. The only things I added were the print_instruction subroutine and its calls, going strictly by what's in the book.

I am using Perl 5.8.8, ActiveState build 820, built Jan. 23, 2007 on Windows XP.

Expand|Select|Wrap|Line Numbers
  1. # hanoi(N, start, end, extra)
  2. # Solve Tower of Hanoi problem for a tower of N disks,
  3. # of which the largest is disk #N.  Move the entire tower from
  4. # peg 'start' to peg 'end', using peg 'extra' as a work space
  5.  
  6. sub print_instruction
  7. {
  8.     my ($disk, $start, $end) = @_;
  9.  
  10.     print "Move disk #$disk from $start to $end.\n";
  11. }
  12.  
  13. hanoi(3, 'A', 'C', 'B', \&print_instruction);
  14.  
  15. sub hanoi
  16. {
  17.     my ($n, $start, $end, $extra, $move_disk) = @_;
  18.  
  19.     if ($n == 1)
  20.     { 
  21.         $move_disk->(1, $start, $end);  # line 27
  22.     } 
  23.     else 
  24.     {
  25.         hanoi($n-1, $start, $extra, $end);             # Step 2
  26.         $move_disk->($n, $start, $end);
  27.         hanoi($n-1, $extra, $end, $start);             # Step 4
  28.     }
  29. }
  30.  
  31. sub print_instruction
  32. {
  33.     my ($disk, $start, $end) = @_;
  34.  
  35.     print "Move disk #$disk from $start to $end.\n";
  36. }
  37.  
Feb 28 '08 #1
Share this Question
Share on Google+
4 Replies


P: 4
Oops, please don't be put off in the above post by the fact that I have two print_instruction subroutines defined. This is not the case in practice. I just copied that code above the call to hanoi() without deleting it from below. Thanks.
Feb 28 '08 #2

KevinADC
Expert 2.5K+
P: 4,059
Hello,

I am trying some code from Higher Order Perl by Mark Jason Dominus and it doesn't work. When I tried to replace the original print statements with a reference to a subroutine (print_instruction) that prints, I kept getting the error message "Undefined subroutine &main:: called at hanoi.pl line 27." Line 27 is marked in the code below in a comment (it shows as line 21 in the posting below). It doesn't like the dereferencing of the subroutine reference I passed in. This was cut and pasted from his website. The only things I added were the print_instruction subroutine and its calls, going strictly by what's in the book.

I am using Perl 5.8.8, ActiveState build 820, built Jan. 23, 2007 on Windows XP.

Expand|Select|Wrap|Line Numbers
  1. # hanoi(N, start, end, extra)
  2. # Solve Tower of Hanoi problem for a tower of N disks,
  3. # of which the largest is disk #N.  Move the entire tower from
  4. # peg 'start' to peg 'end', using peg 'extra' as a work space
  5.  
  6. sub print_instruction
  7. {
  8.     my ($disk, $start, $end) = @_;
  9.  
  10.     print "Move disk #$disk from $start to $end.\n";
  11. }
  12.  
  13. hanoi(3, 'A', 'C', 'B', \&print_instruction);
  14.  
  15. sub hanoi
  16. {
  17.     my ($n, $start, $end, $extra, $move_disk) = @_;
  18.  
  19.     if ($n == 1)
  20.     { 
  21.         $move_disk->(1, $start, $end);  # line 27
  22.     } 
  23.     else 
  24.     {
  25.         hanoi($n-1, $start, $extra, $end);             # Step 2
  26.         $move_disk->($n, $start, $end);
  27.         hanoi($n-1, $extra, $end, $start);             # Step 4
  28.     }
  29. }
  30.  
  31. sub print_instruction
  32. {
  33.     my ($disk, $start, $end) = @_;
  34.  
  35.     print "Move disk #$disk from $start to $end.\n";
  36. }
  37.  
I don't see a problem with the code and It works for me. This is the correct syntax to use with a code reference:

$move_disk->(1, $start, $end)

So I am not sure what the problem is.
Feb 29 '08 #3

P: 4
Below I post the answer as given me by Mark Jason Dominus, the author of "Higher Order Perl" himself. This is the complete text of his reply to my e-mail, quoted here with permission. His reply not only includes the correction to my code, but in doing so clearly explains the cryptic error message as well. I wanted to post it as warning of the kinds of problems one can run into when using recursion if one is not careful.


> I posted this on the web with the code and got only one response. He said
> that he saw nothing wrong with it and that it worked for him.

if he says it worked for him, he's lying.

Here's the problem. hanoi() now takes five arguments.

Here you call it with five arguments:

> hanoi(3, 'A', 'C', 'B', \&print_instruction);

And here it prepares to receive the five arguments:

> sub hanoi
> {
> my ($n, $start, $end, $extra, $move_disk) = @_;


But here you call it with only four arguments:

> hanoi($n-1, $start, $extra, $end); # Step 2
> $move_disk->($n, $start, $end);
> #print "Move disk #$n from $start to $end.\n"; # Step 3
> hanoi($n-1, $extra, $end, $start); # Step 4


So after the first call, the subsequent calls to hanoi() leave
$move_disk undefined.
Mar 5 '08 #4

KevinADC
Expert 2.5K+
P: 4,059
Below I post the answer as given me by Mark Jason Dominus, the author of "Higher Order Perl" himself. This is the complete text of his reply to my e-mail, quoted here with permission. His reply not only includes the correction to my code, but in doing so clearly explains the cryptic error message as well. I wanted to post it as warning of the kinds of problems one can run into when using recursion if one is not careful.


> I posted this on the web with the code and got only one response. He said
> that he saw nothing wrong with it and that it worked for him.

if he says it worked for him, he's lying.

Here's the problem. hanoi() now takes five arguments.

Here you call it with five arguments:

> hanoi(3, 'A', 'C', 'B', \&print_instruction);

And here it prepares to receive the five arguments:

> sub hanoi
> {
> my ($n, $start, $end, $extra, $move_disk) = @_;


But here you call it with only four arguments:

> hanoi($n-1, $start, $extra, $end); # Step 2
> $move_disk->($n, $start, $end);
> #print "Move disk #$n from $start to $end.\n"; # Step 3
> hanoi($n-1, $extra, $end, $start); # Step 4


So after the first call, the subsequent calls to hanoi() leave
$move_disk undefined.
Well, he is also wrong, because here is your original code (less the duplicate function):

Expand|Select|Wrap|Line Numbers
  1. sub print_instruction
  2. {
  3.     my ($disk, $start, $end) = @_;
  4.  
  5.     print "Move disk #$disk from $start to $end.\n";
  6. }
  7.  
  8. hanoi(1, 'A', 'C', 'B', \&print_instruction);
  9.  
  10. sub hanoi
  11. {
  12.     my ($n, $start, $end, $extra, $move_disk) = @_;
  13.  
  14.     if ($n == 1)
  15.     { 
  16.         $move_disk->(1, $start, $end);  # line 27
  17.     } 
  18.     else 
  19.     {
  20.         hanoi($n-1, $start, $extra, $end);             # Step 2
  21.         $move_disk->($n, $start, $end);
  22.         hanoi($n-1, $extra, $end, $start);             # Step 4
  23.     }
  24. }
  25.  
It works just like that, all I did was change the 3 to a 1 here:

hanoi(1, 'A', 'C', 'B', \&print_instruction);

I admit I did not go far enough to test the code, but the author calling me a liar seems rather obtuse. My test was just faulty in that all I did was confim the coderef worked the way you had it, I was not testing the logic of your code for all errors. So forgive me for not being thorough, but I answer many questions on many forums and I sometimes am too hasty.
Mar 5 '08 #5

Post your reply

Sign in to post your reply or Sign up for a free account.