Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

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

by BrowserUk (Pope)
on Jun 17, 2005 at 16:25 UTC ( #467794=note: print w/replies, xml ) Need Help??


in reply to Perl can do it, take 1 (sentence generation)

You can do away with a lot of the punctuation by putting the dereference inside rand_elt() which avoids having it most everywhere else. By predeclaring generate(), you can avoid the need for parens on most of the function calls which cleans it up further.

The final thing of using nested ternaries rather than if / then / else is probably a step too far and will be seen as golfing, but I think it actualy comes closer to the Lisp cond operator (function?).

#! 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 generate; sub generate { my $phrase = shift; return listp( $phrase ) ? map{ generate $_ } @{ $phrase } :exists $dict{ $phrase } ? generate rand_elt $dict{ $phrase } +: $phrase; } print join ' ', generate "sentence";

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^2: Perl can do it, take 1 (sentence generation)
by hding (Chaplain) on Jun 17, 2005 at 16:59 UTC

    For the small minority that might care, cond is specified as a macro: cond Hyperspec entry.

    I believe that it is legal for a Lisp implementation to implement a macro as a special form as long as an equivalent macro version is also provided, but don't quote me on that.

Re^2: Perl can do it, take 1 (sentence generation)
by spurperl (Priest) on Jun 18, 2005 at 05:22 UTC
    But is the ternary-using version really cleaner / clearer to understand than the if/elsif/else chain ?

    Lisp's cond macro is very nice in small functions, but I've seen Lisp function reaching the size of a page (and many have a big cond as their main bulk), it's very hard to follow their logic. I'm starting to think that though if/elsif/else adds a lot of syntax, it's in fact simpler to understand.

    Switches are simpler to follow than conds, because they talk about a single variable, not arbitrary conditions.

      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.
        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)

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2020-05-31 10:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    If programming languages were movie genres, Perl would be:















    Results (173 votes). Check out past polls.

    Notices?