in reply to passing subroutine references

2 of the 4 calls to hanoi only pass 4 arguments when it expects 5.

Update: Specifically,

hanoi( $n - 1, $start, $extra, $end ); $move_disk->( $n, $start, $end ); hanoi( $n - 1, $extra, $end, $start );
should be
hanoi( $n - 1, $start, $extra, $end, $move_disk ); $move_disk->( $n, $start, $end ); hanoi( $n - 1, $extra, $end, $start, $move_disk );

Update: Better fix: (Avoids having a million needless copies of $move_disk)

sub hanoi { my $move_disk = pop(@_); local *_hanoi = sub { my ( $n, $start, $end, $extra ) = @_; if ( $n == 1 ) { $move_disk->( 1, $start, $end ); } else { _hanoi( $n - 1, $start, $extra, $end ); $move_disk->( $n, $start, $end ); _hanoi( $n - 1, $extra, $end, $start ); } }; &_hanoi; } hanoi( $disk, 'A', 'B', 'C', \&check_move ); hanoi( $disk, 'A', 'B', 'C', \&hprint );

Replies are listed 'Best First'.
Re^2: passing subroutine references
by joe76 (Novice) on Sep 18, 2009 at 22:59 UTC

    thank you all for replying. I feel kind of foolish for overlooking that. I knew it had to be something obvious I was missing.

      In my experience, it is often the simple stuff that gives the most problem. The parts of the code you aren't sure about, you will examine carefully, poking and prodding, until they give up their secrets.

      The parts that you understand, on the other hand, hide their secrets in plain sight.

      G. Wade
Re^2: passing subroutine references
by Jenda (Abbot) on Sep 19, 2009 at 10:01 UTC

    I would not call that a better fix. Adds unnecessary complexity and just confuses things. If you do insist that you do not want to have to pass the $move_disk around, it's cleaner to do it like this:

    { my $move_disk; sub hanoi { $move_disk = pop(@_); goto &_hanoi; # (almost) equivalent to _hanoi(@_) } sub _hanoi { my ( $n, $start, $end, $extra ) = @_; if ( $n == 1 ) { $move_disk->( 1, $start, $end ); } else { _hanoi( $n - 1, $start, $extra, $end ); $move_disk->( $n, $start, $end ); _hanoi( $n - 1, $extra, $end, $start ); } }; } hanoi( 3, 'A', 'B', 'C', sub {print "(@_)\n"} );

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

      Your solution to getting rid of complexity is to get rid of a local and add goto &_hanoi;?

      Even a beginner needs to know local, whereas they wouldn't know goto &_hanoi;, and it adds debugging complexities at next to no benefit.

      And at what cost? You've added a global var, you've made the private recursive function public, and you've nested the main function (which seems innocent, but I've found it to cause is to confuse me time and time again).

      I beg to differ. I think you've taken 4 steps back.

        Global? There ain't any global sir. Neither there is any nested function. And _hanoi(@_); would work just as well, while your tricks with local are unavoidable. Besides the problem is not the local itself, but the typeglob handling.

        What debugging complexities are you speaking of?

        Jenda
        Enoch was right!
        Enjoy the last years of Rome.

      but is it really that expensive to do in my original code? aren't we just passing an address to the code, not the code itself?

        Honestly, I don't know how big a waste of memory it is. When it comes to recursive functions, having a big state can be a problem. It's a good idea to avoid a large state unless you can show it's not a problem rather than the other way around. Factoring out unchanging variables is an easy and low-cost way of reducing the size of the state.

        It would be a bigger problem in another language where the stack has a limited size. Perl dynamically allocates each stack frame on the heap, so it's not limited like in C.

        No it's not. We are of course passing just the reference.

        Jenda
        Enoch was right!
        Enjoy the last years of Rome.