Tuesday, May 20, 2008

Added diff and intersect to the Hash object making the primes example even smaller.

/*python version*/
noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
primes = [x for x in range(2, 50) if x not in noprimes]

/*common php version*/
$noprimes = xR(2,8)->mapf('xR($x*2,50,$x)->out()')->flatten();
$primes = xR(2,50)->diff($noprimes);


Or as a lovely one liner


$primes = xR(2,50)->diff(xR(2,8)->mapf('xR($x*2,50,$x)->out()')->flatten());


A little less readable for sure but the reality is it can be done and it fits the true definition of "one liner" by sliding in at the 79th column.

Saturday, May 17, 2008

inline lambda with out a wrapper function

So here is my implementation to allow for inline lambda functions:

This is built on top of my fn (anonymous function which is written to defun directory), fnx (function with one variable called x) and sfnx (single command which should be returned with one variable passed in called x).

The only thing I had to add was a GLOBAL variable called $_ which is an array (I initially called it $L but I like how $_ feels more like a piece of syntax than a variable name). In fn when it gets the name via md5 it then sets $_[$name] = $name; so that you may use it as follows:


echo $_[sfnx('$x')]('hello world');

You can use this how ever you would normally use a function (nested, in function calls etc.)

I mean "with out a wrapper function" because this could be accomplished with a function like: inline($args,$body,$arg1..$argn) which would create the anonymous function and call it with arg1..$argn and return the value.

echo inline('$x','return $x;','hello world');

As you can see it's doable but I guess I like the "feel" of the first one.

I should mention I was inspired by Peter Goodmans i/o reader blog post on a similar tip here: Hacking variable composition - another approach to php lambdas

anonymous function caching

As anyone who has dabbled with php create_function etc. will be able to tell you there are inherent memory leak issues with its implementation. From what I understand it does not apply garbage collection to them for one reason or another (I am going to research this further). Well here is the solution I have been using.

Define a directory where your anonymous methods will sit. I call mine 'defun'.

I have a method called fn($args,$body) which when called will make an md5 of the args+body, this is then prefixed with anon_ and called $name(as it could yield a name with a number as first character which is disallowed in php). I do a file_exists on $name to see if there is a file with that same name (and md5 fingerprint). If not I create it as a proper php file and close it. Then it does a require_once on $name and returns $name as this is what call back methods use to access it.

The only thing I have been worried about is the possibility of md5 collision? Anyway you see an increase of 100% the second time you run a script as it is just doing require_once instead of fwrites.

Friday, May 16, 2008

Prime numbers in PHP

More fluent interface goodness.

// PRIME NUMBERS IN PYTHON
noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
primes = [x for x in range(2, 50) if x not in noprimes]


//PHP
$noprimes = xR(2,8)->for_each('xR($x*2,50,$x)->out()')->flatten();
$primes = xR(2,50)->if_only('!xH('.$noprimes->implode().')->in($x)');


Edited above to reflect the fact I have aliased filterf with if_only (I would love to use if but it is clearly reserved) and mapf with for_each (again would love to use just for, each foreach etc.). Still I feel it reads a lot cleaner.

Purpose

The purpose of this blog is going to be me showing side by side all (well maybe not the ray tracer...) of the exercises from Paul Grahams ANSI Common Lisp in both CLisp and PHP. I will be creating a number of "helper" classes etc. to make the PHP side of things more livable (including a way of caching anonymous functions and thus not ending up with memory leaks... I think).

For now here are some examples of my Fluent Hash class in action with some list comprehension comparisons to python and lisp.


Note that xH and xR are shortcuts for creating a "new Hash" or creating a new hash
and immediately calling it's range method i.e
$new = new Hash();
$new->range(10);

/* python versions
S = [x**2 for x in range(10)]
V = [2**i for i in range(13)]
M = [x for x in S if x % 2 == 0]
P = [str(round(355/113.0, i)) for i in range(1,6)]
F = [x.strip() for x in [' banana', ' loganberry ']]
VEC = [2, 4, 6]
X = [3*x for x in vec if x > 3]
X1 = [[x,x**2] for x in vec]
*/

//PHP
$S = xR(10)->for_each('pow($x,2)');
$V = xR(13)->for_each('pow(2,$x)');
$M = xH($S)->if_only('$x % 2 == 0');
$P = xR(1,6)->for_each('round(355/113.0,$x)');
$F = xH(' banana', ' loganberry ')->map('trim');
$VEC = xH(2,4,6);
$X = xH($VEC)->if_only('$x > 3')->for_each('3*$x');
$X1 = xH($VEC)->for_each('Array($x,pow($x,2))');

/*common lisp
(loop for x from 0 to 100 if (> (* x x) 3) collect (* 2 x))
*/

//PHP
$C = xR(100)->if_only('($x*$x) > 3')->for_each('2*$x');


Now I am wondering if if_x and for_x would work equally well semantically... It would save a few characters but really I feel if_only and for_each are pretty verbose/explicit. One issue is map takes the name of a callback where as for_each takes the body and wraps map.. so semantically for_each should be for_eachu or something to denote it is a user defined function body expected/passsed... OR maybe for_each taking a body and map taking a function actually makes more sense in the first place!?