Am I alone in preferring functional perl to procedural perl? I love using map, grep, map, join type stuff, rather than foreach/for loops to do the same. Today's example was "For each found blacklist entry in the hash, check it's value is true, then call $msg->got_hit() for that blacklist". In procedural perl that's:
foreach my $bl (keys %$blacklists) { if ($blacklists->{$bl}) { $msg->got_hit("RCVD_IN_$bl"); } # alternatively: # $msg->got_hit("RCVD_IN_$bl") if $blacklists->{$bl}; }
map { $msg->got_hit("RCVD_IN_$_") } grep { $blacklists->{$_} } keys %$blacklists;
For the record you have my full support on the use of map in void context. I use if quite often and even find a certain pleasure knowing that it would not pass a certain guru's code reviews
Re:Full support
pudge on 2002-04-17T13:45:52
In case anyone doesn't know and cares, map in a void context is now optimized to not return any values, so it's no longer de facto inefficient.
Re:Full support
Matts on 2002-04-17T14:03:08
I did know, but I didn't know when it was fixed. Do you know which perl fixed that?Re:Full support
pudge on 2002-04-17T14:20:12
My guess is 5.6.0. But I am not sure.Re:Full support
vsergu on 2002-04-17T17:24:39
Various people in the latest TPR golf tournament, including me, had problems related to huge memory usage caused by map() in a void context. The same programs worked fine with for(). We were using 5.6.1.
I didn't think much about it because I didn't know the optimization was supposed to have been done. Plus we all found shorter solutions later on that didn't have the memory problem.Re:Full support
darobin on 2002-04-17T17:36:01
I second that as well, in fact map in void context should be compulsory in Perl code to decide whether it's any good
;) The only time I've been bitten by it is on one of those occasions when I threw a map in naturally, only to notice later that a for loop would have been much simpler. But that's trivial to fix...
Certainly not. Have you seen Dominus' manuscript yet? It's somewhere at http://perl.plover.com, which isn't resolving for me at the moment...Am I alone in preferring functional perl to procedural perl?
For the record, I agree with you 100%. Something's just fun about map, grep, Schwartzian transform, and things like that.
Have you seen Ben Tilly's writeup Why I like functional programming in the monastery? Great stuff.
which seems to communicate the idea more clearly.$msg->got_hit("RCVD_IN_$_") for grep { $blacklists->{$_} } keys %$blacklists;
Re:Maintainability
jjohn on 2002-04-18T12:34:51
Here! Here!
The problem with functional code is that most fresh meat, er, new hires/newbies won't grok what's going on in the code. By using procedural idioms over the functional ones, your code is more likely to be understood by others (and maybe even you) in the future. Using language neutral idioms in public Perl code goes a very long way to squashing Perl's "unmaintainable, spaghetti code" reputation.
Does that mean eschewing
map
andgrep
all together? I don't think so. It is better to limit the use of these operators to idiomatic usage. For instance,grep
is a great way to filter array values.my @private_keys = grep {/^_/ } keys %hash;
map
ought not to be a blank replacement forforeach
, but rather used to create hashes that have easily computed values.my %hashed_names = map{ $_ => md5_hex($_) }@names;If you need to do more complicated things inside a
map
orgrep
please consider using a traditionalfor
orwhile
loop. At some point in the future, I think you'll be glad you did.In the interest of full disclosure, I too went through a phaze where I was all about
map
andgrep
. I now shudder when I look at that code.That said, if you're writing your code just for you, you can get down with your bad functional self.
Re:Maintainability
Matts on 2002-04-18T14:19:30
My favourite current map/grep idiom is:
opendir(DIR, $somedir);
my @files = grep { -f } map { "$somedir/$_" } readdir(DIR);
closedir(DIR);
Nice and succinct, and I think easy to understand (though I should probably be using File::Spec for portability, but *shrug*). I also partly wish you could do filters like this, sort of like SAX pipelines, so I could do something like:
my (@files, @dirs) = grep2 { -f, -d } map { "$somedir/$_" } readdir(DIR);
I'm sure pdcawley will now pipe in how Perl 6 will be able to do this via hyper operators or something;-) Re: Fav. map/grep idioms (Was: Maintainability)
wickline on 2002-04-19T14:53:13
Here's one I've found handy on occasion:
@stuff = sort keys %{{ map {$_ => undef} @stuff }};
gets a sorted list of uniq entries in @stuff.
I always use undef instead of 1 for insignificant hash values because it just *seems* like it should be more efficient. I've never benchmarked any stress-tests though.
-mattRe:Maintainability
ziggy on 2002-04-18T22:34:46
Any style can be abused to produce good or bad Perl code. Erring on the side of "procedural Perl" for the benefit of newbies doesn't mean it will naturally be easier to understand. I've seen grotty Perl code that's using a classic FORTRAN style, so I'd say that it's more important to write clearly than to write in a specific style. I've also seen code that's been massively improved by adopting a functional style in a small scale, without going whole-hog -- in such a way that the fresh meat isn't phased for more than about 5 minutes.By using procedural idioms over the functional ones, your code is more likely to be understood by others (and maybe even you) in the future.:-) Squashing a misperception about Perl isn't your job. Solving a problem in a way that other Perl programmers understand your solution is your job (unless you're writing an Acme::* module, a japh, or a golf swingUsing language neutral idioms in public Perl code goes a very long way to squashing Perl's "unmaintainable, spaghetti code" reputation.:-).