Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re^3: Perl can do it, take 1 (sentence generation)

by BrowserUk (Patriarch)
on Jun 18, 2005 at 09:09 UTC ( [id://467965]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Perl can do it, take 1 (sentence generation)
in thread Perl can do it, take 1 (sentence generation)

Like I said, probably a step too far, but I was trying to stay true to the Lisp original. If the intent is to completely Perlify the algorithm, then you probably wouldn't use the listp() abstraction (and it certainly wouldn't be called that:).

If Perl's if then elsif else construct worked like those in Haskell or SQL, you could do

return if <cond> then <value> elsif <cond2> then <val2> else <val3>;

The nearest I could get is the nested ternaries.

I also tried to code the cond macro, and got pretty close. It follows all the right paths, but implementing rewrite is much harder, and the values don't filter up without that.

#! perl -slw use strict; my %dict = ( sentence => [ [ qw/ noun_phrase verb_phrase / ] ], noun_phrase => [ [ qw/ Article Noun / ] ], verb_phrase => [ [ qw/ Verb noun_phrase / ] ], Article => [ qw/ the a /], Noun => [ qw/ man ball woman table/ ], Verb => [ qw/ hit took saw liked / ] ); sub rand_elt { return @{ $_[ 0 ] }[ rand @{ $_[ 0 ] } ]; } sub listp { return ref $_[0] eq "ARRAY"; } sub cond; sub cond { return shift->() || cond @_; } sub generate; sub generate { my $phrase = shift; warn $phrase.$/; return cond sub{ warn 'A'.$/; return listp( $phrase ) ? map{ generate $_ } @{ $phrase } : () }, sub{ warn 'B'.$/; return exists $dict{ $phrase } ? generate rand_elt $dict{ $phrase } : () }, sub{ warn 'C'.$/; return 1 ? $phrase : () }; }

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.

Replies are listed 'Best First'.
Re^4: Perl can do it, take 1 (sentence generation)
by fergal (Chaplain) on Jun 21, 2005 at 12:54 UTC
    The nearest I could get is the nested ternaries.

    I'd never done this before today but you can use do to achieve the Haskell effect. The do block evaluates to the last expression evaluated.

    for my $i (1..2) { my $v = do { if ($i == 1) { "one"; } else { "not one"; } }; print "i = $i, v = $v\n"; }

    So which is more reabable?

    $v = do {if ($i == 1) { "one" } else { "not one" }; $v = $i == 1 ? "one" : "not one";

    The worry I have about the Haskell way is that it's very easy to accidentally evaluate something else after the if and muck it all up (of this doesn't apply to actual Haskell, just Perl)

      That's quite clever, but that is what I would classify as a 'trick' on the basis that if else elsif are designed conditional invocation of blocks of code.

      The ternary is specifically designed for conditional assignment of values. Not many people baulk at using

      my $min = ( $x < $min ) ? $x : $min;
      . The only problem here is that there are two conditions instead of one, requiring the use of chained ternaries. But then, noone baulks at using nested or chained ifs, and the structure of the code is identical.

      And is it really any clearer?

      #! perl -slw use strict; for ( 1 .. 3 ) { print do{ if( $_ == 1 ) { 'one' } elsif( $_ == 2 ) { 'two' } else{ 'three' } }; print $_ == 1 ? 'one' : $_ == 2 ? 'two' : 'three'; }

      To my eyes, the former is not even slightly clearer than the latter, but then I use this construct freely, when applicable and so I am used to seeing it and it presents me with no problems to read it. Especially if it is formatted well.

      Indeed. The only reason why some of Perl's more obscure contructs are eshewed by some, is because they are obscure. It's a self-propogating argument. If more people used them, they would less obscure--more familiar--and the reason for not using them diminishes.

      I'd go even further and say that using the appropriate operators for the operation has further benefits:

      1. It prevents the confabulations of program logic.

        By this I mean that it forces a separation between different operations in a way that clarifies the code.

        Example: Given the code:

        my $var; if( <cond1> ) { $var = <somevalue>; } elsif( <cond2> ) { $var = <someothervalue>; } else { $var = <default>; }

        A spec change or bug fix results in this modification:

        my $var; if( <cond1> ) { $var = <somevalue>; doSomething; } elsif( <cond2> ) { $var = <someothervalue>; doSomethingElse; } else { $var = <default>; }

        I would much rather see that coded as:

        my $var = <cond1> ? <somevalue> : <cond2> ? <someothervalue> : <default>; doSomething if $var == <somevalue>; doSomethingElse if $var == <someothervalue>;

        To me, it much more clearly captures the semantics of the code.

      2. It provides less opportunities for someone to come along and interperse code performing unrelated notions into the conditional blocks.
      3. To a certain extent, even the fact that it may force later visitors to the code to actually read the code, rather than just scanning it, is itself a plus.

        I'm as guilty as the next man, perhaps more so, of scanning a piece of code and seeing what I think it does instead of what it actually does. If code that does conditional assignment to a variable, looks like an assignment to a variable (with conditions)

        my $var = ......;
        , That is more likely to register as that than if it looks like a declaration of a variable followed by a set of conditional blocks of code:
        my $var; if( ... ) { $var = ...; } elseif( ... ) { $var = ...; } else { $var = ...; }

        Where the primary purpose of the code is lost in it's construction.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.

        I'm not really recommending it as a good idea, just pointing out that it can be done and is pretty much the direct translation of cond. That said, the problem with doing other stuff in the blocks only arises when you leave the realms functional programming and start using side-effects (and in fact mixing side effect with returning values).

        I just tried something interesting:

        my ($x, $y) = (0,0); for my $i (1..2) { do { if ($i == 1) { $x; } else { $y; } } = 7; print "i = $i, x = $x, y = $y\n"; }

        This doesn't work but it would have worked with an lvalue sub so why not allow lvalue do blocks.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (7)
As of 2024-03-28 21:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found