High Performance Linux

Tuesday, January 10, 2012

List Comprehensions in Perl

Some time ago I found List comprehension article in Wikipedia. There are many examples for languages which natively support List Comprehension (mainly functional languages), but also few examples of similar constructs for languages which have not embedded list comprehension.I wonder why there is no Perl examples.

Although Perl doesn't have native list comprehension it is very easy to do with map and grep constructions. Let's consider couple of examples.

At first lets see how to implement example of list comprehension construction for Python from the article (I replaced 101 by 5 for shorter output):

$ python -c 'print [2 * x for x in range(5) if x ** 2 > 3]'
[4, 6, 8]

In Perl it would be (Dumper output is reformatted for brevity):

$ perl -MData::Dumper -e 'print Dumper([map { $_ * 2 } \
                                        grep { $_ ** 2 > 3 } (0..4)])'
$VAR1 = [4, 6, 8];

Other example for list of lists generation

$ python -c 'print [(i,j) for j in range(2, 5) for i in range(1,j)]'
[(1, 2), (1, 3), (2, 3), (1, 4), (2, 4), (3, 4)]

and its Perl analog is (Dumper output is reformatted for brevity)

$ perl -MData::Dumper -e 'print Dumper([map { $n = $_; \
                                        map {[$_,$n]} (1..$n - 1)} \
$VAR1 = [
          [1, 2],
          [1, 3],
          [2, 3],
          [1, 4],
          [2, 4],
          [3, 4]

Thursday, January 5, 2012

Tail Recursion in Perl and Python (or why do we prefer Perl to Python)

Few years ago I was making several Python projects. I moved from Perl to Python because of its clearer syntax and it was just interesting for me to know why so much people (like Google and Yandex) moved to Python.

However I back to Perl after two years with Python. Python is good mature language with great modules and scalable preemptive multi-threading support (unlike Ruby which uses cooperative multi-threading for 1.8 and global interpreter lock (GIL) for current 1.9 version). But programming in Python becomes quite tedious if you wish to do some unusual things.

Lets consider following simple example of recursive factorial calculation:

sub tail_factorial
        my ($total, $n) = @_;

        return $total unless $n;
        return tail_factorial($total * $n, $n - 1);

In Python this code looks like (also quite short and straightforward):

def tail_factorial(total, n):
        if not n:
                return total
        return tail_factorial(total * n, n - 1)

Perl5 does not have tail recursion optimization (unlike Perl6). The same story with Python3.However there is simple solution for Perl (example is borrowed from Pure Perl tail call optimization, changed lines are in italic):

sub tail_factorial2
        my ($total, $n) = @_;

        return $total unless $n;

        @_ = ($n * $total, $n - 1);
        goto &tail_factorial2;


However I was wondered that there is no clear solution for Python. There is decorators implementations (see Tail Call Optimization Decorator (Python recipe) or Tail recursion decorator revisited), but all of them uses additional functions and internal loops. Other solutions are Tail Recursion in Python using Pysistence and Tail recursion in Python also uses internal cycles and helping functions.

Guido has stated about such solutions in his blog as "it's simply unpythonic". This is bit unnatural example and really there is no big deal to rewrite the function to use a loop (we live with the practice in kernel programming for a long time). However actually there are plenty of such limitations with Python (one more good example is that you can not call Python program as a single line, so you can not buili it into shell scripts and use it as extended sed/awk for advanced grep'ing). Thus I prefer to work with powerful and flexible tool rather than with limited and poor. This is why we use Perl in our daily work.