Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re^3: Multi-stage flip-flop? ( till() - proof of concept)

by RonW (Parson)
on Dec 12, 2014 at 02:44 UTC ( [id://1110115]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Multi-stage flip-flop? ( till() - proof of concept)
in thread Multi-stage flip-flop?

After refining my code from Re^6: Multi-stage flip-flop?, my proof of concept where conditions are only evaluated in the corresponding state.

#!perl -w =begin DoxPod =pod @file Multi Flip-Flop. Provides functionality like Perl's flip-flop operator ( C<...> ) with the added feature of additional states. =cut use warnings; use strict; use Carp; my %states; #< Holds state based on where called from. sub _lookupState { my ($f, $l) = @_[1,2]; return $states{"$f,$l"}; } sub _saveState { my ($s, $x, $f, $l) = @_[0 .. 3]; $states{"$f,$l"} = $s; } sub mff { my $state = _lookupState(caller); $state = 0 unless defined($state); croak('Fatal: mff: Too few conditions for current state.') if ((2 * $state) >= @_); my $type = ref($_[2 * $state]); $type = ref(\$_[2 * $state]) if ($type eq ''); if ($type eq 'SCALAR') { $state++ if ($_[2 * $state]); } elsif ($type eq 'Regexp') { $state++ if (/$_[2 * $state]/); } elsif ($type eq 'CODE') { $state++ if ($_[2 * $state]->($_)); } else { croak("Fatal: mff: Unsupported type: $type"); } _saveState($state, caller); if ((2 * $state) >= @_) { # final condition was true _saveState(0, caller); return 0; } return 0 if ($state < 1); # init condition still false return $_[(2 * $state) - 1]->($_); } sub s1 { print "1:$_\n"; } sub s2 { print "2:$_\n"; } sub s3 { print "3:$_\n"; } while (<DATA>) { chomp; mff(qr/alpha/ => \&s1, qr/beta/ => \&s2, qr/gamma/ => \&s3, qr/omega/) or print "*:$_\n"; } __DATA__ This is the alpha but not the omega Now the beta progressing to the gamma and finally the omega Did this work?

And the output:

*:This is 1:the alpha 1:but not 1:the omega 2:Now the beta 2:progressing to 3:the gamma 3:and finally *:the omega *:Did this work?

To do: Add tests for code and scalar based conditions.

Replies are listed 'Best First'.
Re^4: Multi-stage flip-flop? ( till() - proof of concept)
by LanX (Saint) on Dec 12, 2014 at 03:00 UTC
    Your concept of passing the condition only works when testing a global var like $_ and typechecking is vulnerable in edge cases.¹

    I think my concept is more robust and any boolean test can be used.

    Sometimes less is more.

    use strict; use warnings; use Data::Dump; { my %state; sub till { my @phases=@_; #dd \@_; my ($file,$line)= (caller)[1..2]; my $state = \$state{$file,$line}; $$state //= 0; $phases[1+$$state]->(); if ($phases[$$state]) { $$state += 2; $$state %= @phases; } } } while (my $var = <DATA>){ till ( - ($var =~ /for/) => sub { print "*: $var" }, - ($var =~ /their/) => sub { print "1: $var" }, - ($var =~ /fruit/) => sub { print "2: $var" }, - ($var =~ /lazy/) => sub { print "3: $var" }, ); } __DATA__ now is the time for all good men to come to the aid of their party. Time flies like an arrow fruit flies like a banana. The quick red fox jumps over the lazy brown dog. Etaoinshrdlu.

    out

    *: now is the time *: for all good men to 1: come to the aid of 1: their party. 2: Time flies like an arrow 2: fruit flies like a banana. 3: The quick red fox 3: jumps over the lazy *: brown dog. *: Etaoinshrdlu.

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

    ¹) What if a test returns a reference for true? Enforcing negation with a unitary minus solves this issue.

Re^4: Multi-stage flip-flop? ( till() - proof of concept)
by RonW (Parson) on Dec 12, 2014 at 20:23 UTC

    (Updated to add explanation of the error in the scalar test.)

    I added tests for code references and scalars as conditions:

    sub c3 { print "Evaluating condition 3\n"; /gamma/; } sub c4 { print "Evaluating condition 4\n"; /omega/; } while (<DATA>) { chomp; mff(qr/alpha/ => \&s1, qr/beta/ => \&s2, \&c3 => \&s3, c4() ) or print "*:$_\n"; }

    In the above, a code ref to c3 is passed. c4, however, is called and its result, a scalar, is passed.

    The results:

    Evaluating condition 4 *:This is Evaluating condition 4 1:the alpha Evaluating condition 4 1:but not Evaluating condition 4 1:the omega Evaluating condition 4 2:Now the beta Evaluating condition 4 Evaluating condition 3 2:progressing to Evaluating condition 4 Evaluating condition 3 *:the gamma Evaluating condition 4 *:and finally Evaluating condition 4 *:the omega Evaluating condition 4 *:Did this work?

    c3, which was passed as a code ref, was evaluated only in state 2, as expected. So, conditions passed as code refs do work.

    c4, because it is called before calling mff, is evaluated every iteration, as expected. However, there is an error: mff transitioned to the "inactive" state too soon.

    Update: changing the call to c4 to !!c4() "fixed" the test. The !! imposes scalar context on the call to c4. (It also "imposes" boolean context. Note that +c4() or -c4() would also have worked.)

    Note: LanX raises a valid point: "What if a test returns a reference?" That depends on what the reference points to. If a scalar, then the scalar value is tested. If a regex, it is evaluated against $_. If code, it is evaluated and its return value tested. If another reference, that reference is treated as a scalar.1 If anything else, mff croaks with the message "Unsupported type".

    I think flip-flop ( .. ) handles refs to scalars, regexen and code the same. Given that ref(ref(any)) eq 'SCALAR', I suspect it handles refs to refs the same as scalars. Refs to anything else, I don't know. More testing needed.

    ---

    1 I tested print ref(ref(1)) and print ref(ref(qr/foo/)) and print ref(ref(sub { print 1; })) and several others. Each time, the result was SCALAR

Re^4: Multi-stage flip-flop? ( till() - proof of concept)
by LanX (Saint) on Dec 12, 2014 at 12:34 UTC
    The CODE part shouldn't work left from a fat comma.

    Keys are always a stringifyed!

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

      I added a "code ref" test:

      sub c3 { print "Evaluating condition 3\n"; /gamma/; } while (<DATA>) { chomp; mff(qr/alpha/ => \&s1, qr/beta/ => \&s2, \&c3 => \&s3, qr/omega/ ) or print "*:$_\n"; }

      The output:

      *:This is 1:the alpha 1:but not 1:the omega 2:Now the beta Evaluating condition 3 2:progressing to Evaluating condition 3 3:the gamma 3:and finally *:the omega *:Did this work?

      Which is what I expected.

      Apparently, the "fat comma" ( => ) only quotes bare words. chromatic claims the same in the first paragraph of http://www.modernperlbooks.com/mt/2013/04/the-fat-comma-and-clarity.html.

      So, => is not imposing string context on \&c3 so that doesn't get stringified.

        ah yes right!

        The trap was that hash keys are always strings, but while the arguments look like a hash structure they aren't real keys and values.

        I remember now that I fell into this trap before...

        But still, when passing values which are supposed to be boolean it's safer to negate them.

        Cheers Rolf

        (addicted to the Perl Programming Language and ☆☆☆☆ :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1110115]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-20 02:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found