Sunday, February 17, 2008

Perl nested lists vs. Python and Lisp.

It is no nested lists in Perl. However, Python and Lisp have this ability.

Description of implementing in Perl equivalent structure to nested Python and Lisp lists given.

Used:

$ python --version
Python 2.5.1
$ perl -v | head -2

This is perl, v5.8.8 built for i486-linux-gnu-thread-multi
$ clisp --version | head -1
GNU CLISP 2.41 (2006-10-13) (built 3371977993) (memory 3401903509)


Consider
'(1 (2 (3) 4) 5)
lisp list as the example of data structure we work with:

$ clisp
...
[1]> (setq alist `(1 (2 (3) 4) 5))
(1 (2 (3) 4) 5)
[2]> (elt alist 0)
1
[3]> (elt alist 2)
5
[4]> (elt alist 1)
(2 (3) 4)
[5]>

Corresponding interactive session for Python:

>>> a = [1, [2, [3], 4], 5]
>>> print a
[1, [2, [3], 4], 5]
>>> print a[0]
1
>>> print a[1]
[2, [3], 4]
>>> print a[2]
5



Python in list processing is very like Lisp. The difference for defining list body is only using commas and square brackets in python, and you don't need put quote sign before it. (As done in Lisp to interpret it as list, not executing as function).

Perl is different in this point. Perl instead of interpreting list as given, removes all parens inside.


$ perl -e '@al = (1, (2, (3), 4), 5); \
print "\@al[0]=@al[0] , \@al[1]=@al[1] , \@al[2]=@al[2] ,\
\@al[3]=@al[3] , \@al[4]=@al[4] \n"; \
print @al; print "\n"; '
@al[0]=1 , @al[1]=2 , @al[2]=3 , @al[3]=4 , @al[4]=5
12345


Lisp has very convenient data model, all data in lisp are pointers.
And the solution of implementing nested lists in Perl is pointer based.

Pointer to list in perl uses square brackets ([]), like lists syntax in Python.
So our structure look is:

$al = [1, [2, [3], 4], 5];


Following procedure prints elements, emulating output in Python session and Common Lisp REPL:


sub slistp($)
{
my ($listp) = @_;
my $i;
my $ret = "";
if (ref($listp) eq 'ARRAY')
{
$ret = "[";
$ret .= slistp(@$listp[0]);
for ($i=1;$i<(scalar @$listp);$i++)
{
$ret .= ",";
$ret .= slistp(@$listp[$i]);
};
$ret .= "]";
}
else
{
$ret .= $listp;
}
return($ret);
}


Usage for our list:
$al = [1, [2, [3], 4], 5];
print "\@al[0]=".@$al[0].", \@al[1]=@$al[1] , \@al[2]=@$al[2] \n";
print slistp($al);
print "\n";
print "\@al[0]=".slistp(@$al[0])."\n\@al[1]=".slistp(@$al[1]);
print "\n\@al[2]=".slistp(@$al[2])."\n";

result of complete code execution:
$ perl nestlist.pl
@al[0]=1, @al[1]=ARRAY(0x8152b44) , @al[2]=5
[1,[2,[3],4],5]
@al[0]=1
@al[1]=[2,[3],4]
@al[2]=5


So for Perl lisp-based tree structures, list references have to be used instead of lists.

Additional fees for dereferencing array pointers applied in Perl syntax.
It is no REPL integrated session in Perl, and examining complex structures based on lists require usage of additional modules, or writing own functions. Therefore Python, and especially Lisp are more preferable for list processing tasks.

No comments: