in reply to Closures and sort

I'd go with that:
use strict; my @list = qw/ box cow dog apple ant/; { my $count = 0; sub get_count { return $count } # an inspector as a closure # and another closure sub compare { $count++; return $_[0] cmp $_[1]; } } print sort { compare( $a, $b ) } @list; print "\n"; print get_count();

Replies are listed 'Best First'.
Re: Re: Closures and sort
by traveler (Parson) on Aug 04, 2003 at 20:58 UTC
    Hmmm, it seems as though this solution does not make count unique to each sort. Thus $count contains a cumulative count as opposed to a count for each sort. I guess I should have stated my goals at the beginning.

    --traveler

      The obvious answer would be to add a method reset_count() in the block, but you would have to explicitly call it before sorting, which is prone to errors.

      Another way is to put together a state and a behaviour, building an object.

      But if you want to go on in a functional way, you may want to build a composition of a behaviour and a state, i.e. a closure. Here a short demonstration:
      use strict; my @list1 = qw/ box cow dog apple ant/; my @list2 = qw/ ant apple box cow dog/; sub make_a_profilable_sorter { my $criterion = shift; return sub { my $counter = 0; my @list = @_; @list = sort { $counter++; $criterion->( $a, $b ) } @list; return ( $counter, @list ); } } my $sorter1 = make_a_profilable_sorter( sub{ $_[0] cmp $_[1] } ); my $sorter2 = make_a_profilable_sorter( sub{ $_[0] cmp $_[1] } ); my ($count, @res) = $sorter1->( @list1 ); print "I sorted /@list1/ in $count steps producing /@res/\n"; my ($count, @res) = $sorter2->( @list2 ); print "I sorted /@list2/ in $count steps producing /@res/\n";
      In order to learn more about this subject (very interesting, in my opinion) you could refer to the following online resources:
        Thank you. In case it is not obvious I am trying to learn to do functional programming in perl. I have done it in lisp, but am trying to move my understanding to perl. Your code is where I thought I was going in the first place. My mistake was trying to put the sort outside the closure.

        --traveler

      That's becauase this is a closure and $count retains its value between calls, since there is actually an instance of $count being carried around in the coderef.

      Either move $count into the outer scope, so you can clear it between calls, or generate a new set closures, modding the previous poster's code Re: Closures and sort :

      use strict; my @list = qw/ box cow dog apple ant/; sub mksub { my $count = 0; my $s1 = sub { return $count }; # an inspector as a closure # and another closure my $s2 = sub { $count++; return $_[0] cmp $_[1]; }; return ( $s1, $s2 ); } my ( $get_count, $compare, ); ( $get_count, $compare, ) = mksub(); print sort { $compare->( $a, $b ) } @list; print "\n"; print $get_count->(), "\n"; print "\n"; print sort { $compare->( $a, $b ) } @list; print "\n"; print $get_count->(), "\n"; print "\n"; ( $get_count, $compare, ) = mksub(); print sort { $compare->( $a, $b ) } @list; print "\n"; print $get_count->(), "\n"; print "\n";
      Which produces:
      antappleboxcowdog
      9
      
      antappleboxcowdog
      18
      
      antappleboxcowdog
      9
      
      Update: as someone else said, creating a reset_count coderef inside the same scope would do this and be cleaner than what I did.

      --Bob Niederman, http://bob-n.com
        Phooey. Bit by the nested subs "feature". Thank you.
Re: Re: Closures and sort
by traveler (Parson) on Aug 04, 2003 at 20:54 UTC
    You're right, this is much easier than returning a list. I should have thought of an inspector and a block. Thanks.

    --traveler