Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Imperative VS Functional - Imperative wins?

by bennymack (Pilgrim)
on Mar 23, 2007 at 17:44 UTC ( [id://606303]=perlquestion: print w/replies, xml ) Need Help??

bennymack has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perl Mavens,

I was messing around with a simple chunk of imperative code and I was curious if flipping it around into a functional one-liner would make it faster. But apparently not... Although my method of doing so was most likely NOT optimal as is normally the case.

I have a feeling the answer is in the layout of the bytecode so I've posted it here for the convenience of the monks who cannot compile to byte code in there head 8^)=

Imperative

$ perl -MO=Concise -e ' my @tokens = split /\:\:/, $ARGV[0]; return ( q[], $tokens[0] ) if scalar( @tokens ) == 1; return ( $tokens[0], $tokens[1] ) if scalar( @tokens ) == 2; my $function = pop @tokens; return ( join( q[::], @tokens), $function ); '
1c <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:2) v ->3 a <2> aassign[t3] vKS ->b - <1> ex-list lK ->8 3 <0> pushmark s ->4 7 <@> split[t2] lK ->8 4 </> pushre(/"::"/) s/64 ->5 - <1> ex-aelem sK/2 ->6 - <1> ex-rv2av sKR/1 ->- 5 <$> aelemfast(*ARGV) s ->6 - <0> ex-const s ->- 6 <$> const(IV 0) s ->7 - <1> ex-list lK ->a 8 <0> pushmark s ->9 9 <0> padav[@tokens:1,3] lRM*/LVINTRO ->a b <;> nextstate(main 2 -e:3) v ->c - <1> null vK/1 ->m f <|> and(other->g) vK/1 ->m e <2> eq sK/2 ->f - <1> scalar sK/1 ->d c <0> padav[@tokens:1,3] s ->d d <$> const(IV 1) s ->e l <@> return KP ->m g <0> pushmark s ->h h <$> const(PV "") s ->i k <2> aelem sK/2 ->l i <0> padav[@tokens:1,3] sR ->j j <$> const(IV 0) s ->k m <;> nextstate(main 2 -e:4) v ->n - <1> null vK/1 ->z q <|> and(other->r) vK/1 ->z p <2> eq sK/2 ->q - <1> scalar sK/1 ->o n <0> padav[@tokens:1,3] s ->o o <$> const(IV 2) s ->p y <@> return KP ->z r <0> pushmark s ->s u <2> aelem sK/2 ->v s <0> padav[@tokens:1,3] sR ->t t <$> const(IV 0) s ->u x <2> aelem sK/2 ->y v <0> padav[@tokens:1,3] sR ->w w <$> const(IV 1) s ->x z <;> nextstate(main 2 -e:5) v ->10 13 <2> sassign vKS/2 ->14 11 <1> pop sK/1 ->12 10 <0> padav[@tokens:1,3] lRM ->11 12 <0> padsv[$function:2,3] sRM*/LVINTRO ->13 14 <;> nextstate(main 3 -e:6) v ->15 1b <@> return KP ->1c 15 <0> pushmark s ->16 19 <@> join[t5] sK/2 ->1a 16 <0> pushmark s ->17 17 <$> const(PV "::") s ->18 18 <0> padav[@tokens:1,3] l ->19 1a <0> padsv[$function:2,3] ->1b -e syntax OK

Functional

$ perl -MO=Concise -e 'return map({join(q[::], @$_[0 .. $#$_ - 1]), $$_[$#$_];} [split(/::/, $ARGV[0], 0)]);'
17 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 2 -e:1) v ->3 16 <@> return K ->17 3 <0> pushmark s ->4 d <|> mapwhile(other->e)[t9] K/1 ->16 c <@> mapstart K*/2 ->d 4 <0> pushmark s ->5 - <1> null lK/1 ->5 - <1> null lK/1 ->d - <@> scope lK ->d - <0> ex-nextstate v ->e 13 <@> list lK ->- e <0> pushmark s ->f u <@> join[t6] sK/2 ->v f <0> pushmark s ->g g <$> const(PV "::") s ->h t <@> aslice lK ->u h <0> pushmark s ->i - <1> null lK/1 ->q p <1> flop lK ->q 15 <1> flip[t5] lK/LINENUM ->q i <|> range(other->j)[t4] lK/1 + ->14 14 <$> const(IV 0) s ->15 o <2> subtract[t3] sK/2 ->p m <1> av2arylen sK/1 ->n l <1> rv2av[t2] sKR/1 + ->m k <1> rv2sv sKM/DR +EFAV,1 ->l j <$> gv(*_) s +->k n <$> const(IV 1) s ->o s <1> rv2av[t1] sKR/1 ->t r <1> rv2sv sKM/DREFAV,1 ->s q <$> gv(*_) s ->r 12 <2> aelem sK/2 ->13 x <1> rv2av sKR/1 ->y w <1> rv2sv sKM/DREFAV,1 ->x v <$> gv(*_) s ->w 11 <1> av2arylen sK/1 ->12 10 <1> rv2av[t7] sKR/1 ->11 z <1> rv2sv sKM/DREFAV,1 ->10 y <$> gv(*_) s ->z b <1> srefgen sKM/1 ->c - <1> ex-list lKRM ->b a <@> anonlist sKRM/1 ->b 5 <0> pushmark s ->6 9 <@> split[t8] lK ->a 6 </> pushre(/"::"/) s/64 ->7 - <1> ex-aelem sK/2 ->8 - <1> ex-rv2av sKR/1 ->- 7 <$> aelemfast(*ARGV) s ->8 - <0> ex-const s ->- 8 <$> const(IV 0) s ->9 -e syntax OK

And the output of the benchmark looks something like this:

Rate functional_3 functional_2 imperative_3 functiona +l_1 imperative_2 imperative_1 functional_3 245059/s -- -12% -16% - +24% -36% -54% functional_2 278368/s 14% -- -5% - +13% -28% -48% imperative_3 292322/s 19% 5% -- +-9% -24% -45% functional_1 321554/s 31% 16% 10% + -- -17% -39% imperative_2 385506/s 57% 38% 32% +20% -- -27% imperative_1 531129/s 117% 91% 82% +65% 38% --

Thanks for any insights you can lend. Sorry if any of my terms are misleading/incorrect.

Replies are listed 'Best First'.
Re: Imperative VS Functional - Imperative wins?
by dragonchild (Archbishop) on Mar 23, 2007 at 19:03 UTC
    Without a seriously powerful compiler (like what various Lisps or Haskells provide), functional programming will always run slower than imperative programming. That's not what functional programming is for. It's for developer efficiency, not CPU efficiency. It's the reason we use Perl and not Java.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Imperative VS Functional - Imperative wins?
by ferreira (Chaplain) on Mar 23, 2007 at 19:07 UTC

    Your comparison does not look very fair. Both codes:

    sub foo { my @tokens = split /\:\:/, shift; return ( q[], $tokens[0] ) if scalar( @tokens ) == 1; return ( $tokens[0], $tokens[1] ) if scalar( @tokens ) == 2; my $function = pop @tokens; return ( join( q[::], @tokens), $function ); }
    and
    sub bar { return map({join(q[::], @$_[0 .. $#$_ - 1]), $$_[$#$_];} [split(/::/ +, shift)]); }
    look like very convoluted ways to split a module name into two parts. Maybe something simpler as
    sub boo { my $a = shift; if ($a =~ /^(?:(.*)::)?(.*)$/) { return ($1 || '', $2); } }
    would work too. Using map for a 1-element array does not seem very efficient. Deconstructing a string with split to get it together with join does not seem optimal as well.

Log In?
Username:
Password:

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

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

    No recent polls found