Friday, July 3, 2009

php 5.3 y combinator and other musings

Whenever I get excited about php 5.3 and start foaming at the mouth about lambdas/closures etc. I think I probably just come off like a wing nut. So here is the "canonical example" converted from the work of this dudes javascript example:

function apply(){
$args = func_get_args();
return call_user_func_array(array_shift($args), $args);

function Y($f) {
$recur = function($r) use($f) {
return function($n) use ($f, $r) {
return apply($f($r($r)), $n);
return $recur($recur);

$fibo = Y(function($f) {
return function($n) use ($f) {
if($n <= 2) {
return 1;
} else {
return $f($n - 1) + $f($n - 2);

echo $fibo(15); #610

You'll notice the main trick is the explicit closures using the "use" keyword. I think I almost DO like this solution as it is rather explicit about what vars you are closing over.

Here is another example taken from the first chapter of SICP:

define('tolerance', 0.00001);

function fixed_point($f, $first_guess){
$close_enough = function($v1, $v2){
return (abs($v1 - $v2) < tolerance);

$try = function($guess) use(&$try, $f, $close_enough){
$next = $f($guess);
return $close_enough($guess, $next) ? $next : $try($next);

return $try($first_guess);

echo fixed_point('cos', 1.0); #0.7390822985224
echo fixed_point(function($y){return sin($y) + cos($y);}, 1.0); #1.2587315962971

Other than the ugliness that is the mandatory return statements and semi-colons even for the last/only statement in a function... I actually sort of dig this.

The only trick in this example is "use(&$try, ..." clause which passes a ref to $try so the function can call itself.

Here are some more cool scheme tricks. Creating cons, car, cdr, lst etc. from closures:

function cons($x, $y){
return function($m) use(&$x, &$y){
return $m ? $x : $y;

function car($z){ return $z(true); }

function cdr($z){ return $z(false); }

define('nil', null);

function lst(){
$args = func_get_args();
return cons(
empty($args) ? nil : call_user_func_array('lst', $args));

function length($items){
return $items == nil ?
0 :
1 + length(cdr($items));

function append($list1, $list2){
return $list1 == nil ?
$list2 :
cons(car($list1), append(cdr($list1), $list2));

Obviously the performance implications here have not been explored - it's purely academic but interesting to see what is now possible.

Want to implement your own objects? Here is a perl-esque approach returning a hash of functions and using a ref to $self for accessing methods within the object:

function person($age){
$self = array(
'get_age' => function() use(&$age){
return $age;
'set_age' => function($new_age) use(&$self, &$age){
$age = $new_age;
return $self['get_age']();
return $self;
$peter = person(20);
echo $peter['get_age'](); #20
echo $peter['set_age'](50); #50
echo $peter['get_age']() #50

Another thought that came to mind was "ghetto macros" by either abusing the $GLOBALS var to create functions or returning an array one could extract into an environment of their choice. Behold:

function many_methods($name, $x){
$GLOBALS['get_'.$name] = function() use(&$x){
return puts($x);

$GLOBALS['set_'.$name] = function($y) use(&$x){
$x = $y;
many_methods('tony', 20);
$get_tony(); #20
$set_tony(500); #500
$get_tony(); #500

function clean_many($name, $x){
return array(
'get_'.$name => function() use(&$x){
return puts($x);
'set_'.$name => function($y) use(&$x){
$x = $y;

function inner_scope(){
extract(clean_many('walter', 400));

etc. etc. etc.

No comments: