terminal-auspicious

Topics

programming

php drupal scheme scheming macros design patterns da la

design

design css

random thoughts

scribbles

alter ego

other me 'em that link us my space me linked in

Collections

Programmable web
PHP design patterns

Similar things

  • Emulating closures in PHP
  • Some ways to use saved state with closures in php
  • Learning lessons from Lisp or patterns and languages in PHP
  • macro processor - initial notes
  • Scoped php functions or more ways to abuse php
  • Overcomplicated design pattern implementations
  • out of the (php) loop
  • Googles Summer of yawn.
  • Poor man's macro programming in php
  • macros, higher-order functions, datatypes and design patterns

guild
Home » blogs » vlado's blog

LISP-like programming in php

Submitted by vlado on Thu, 2006-06-22 13:12.lisp | php | scheme | scribbles

My obsession with things schemish and lispish and having to use php on a daily basis leads to the usual comparison and how would I do this in ... style questions. So here comes another go at how would I program lisp style in php. How much is possible? What is possible? Mind you not everything is really useful or the best way to do it. It is just an intellectual excersise, a study on using some of the php'f features to program in not a typical php (imperative) style.

the compulsory conses, car, cdr in php

Well for the benefit of non-lispers I will use head and tail instead of car and cdr respectively.

function head($list) { return array_shift($list); }

The natural equivalent native structure to a lisp list would be a php array. Ok, nearly equivalent. I don't want to go into too much detail at this point.

function tail($list) { array_shift($list); return $list; }
function cons() { return func_get_args(); }

These two are driven by the same assumptions as before. You can see that there is a nice symmetry between them. In cons the argument list is used as a LISP or Scheme list would be used.

lisp-like quotes in php

function quote() { return func_get_args(); }

That was easy. It does not do anything to really quote the arguments of the function, so you need to manually quote everything you need. A typical application would be something like: $x = quote('printer', 'two', 'three' ); unquote( $x ); Well in order to make better sense here's the reverse unquote function unquote( $list ) { $calleable = array_shift($list); return call_user_func_array($calleable, $list); }

Apply

function apply() { $args = func_get_args(); $func = shift($args); return call_user_func_array( $func, $args); } Apply is an alias to the native call_user_func_array(). Is there an need to explain more?

a scheme like begin

function begin() { $args = func_get_args(); for($k = func_num_args(), $i=0; $i<$k; $i++) { $out = is_callable( $args[$i] )? call_user_func($args[$i]): $args[$i]; } return $out; }

This will allow for sequencing functions begin( some_function_application, some_other_function) Note that all the arguments to begin are either thunks, functions with no arguments, or self-evaluating, non-calleables.

php thunks in trunks

This time, it will be a class based implementation. It doesn't need to be, but let's vary the techniques. class thunk { var $args; var $name; function thunk() { $args = func_get_args(); if($args[0][0]=='make') { $args= $args[0]; array_shift($args); } $name = array_shift($args); $this->args = $args; $this->name = $name; } function ammend() { $this->args = array_merge($this->args, func_get_args()); } function call() { $args = $this->args; $name = $this->name; if( func_num_args() ) { $args = array_merge($this->args, func_get_args()); } return call_user_func_array($name,$args); } }

And thunk's little helpers:

function is_thunk( $obj ) { return is_a($obj,'thunk'); }
function make_thunk() { $args = func_get_args(); if( is_thunk( $args[0][0] ) ) { $obj = array_shift($args); $obj =& $obj[0]; $obj->ammend($args); } else { array_unshift($args,'make'); $obj = new thunk( $args ); } return array($obj, 'call'); }

There is a lot of sugar here. The implementation could have been far leaner, but I wanted to be able to mimic partial evaluation, hence this code. It is not really a thunk - remmember, a thunk is any valid php callback which doesn't require arguments.

A lightweight lazy (delayed) evaluation

Using the above definitions: function delay() { $args = func_get_args(); return make_thunk($args); }

This is an implemention of a lazy function. It returns a promise, which when forced will execute the delayed function.

function force( $thunk ) { return call_user_func( $thunk ); }

An example force implementation, which essentially is an alias for the native call_user_func.

One of the few essentials left is lambdas. I'll leave the implementation for the eager reader for the time being. The only reall catch for implementing lambda() is scoping. Otherwise the code will look very close to the thunk one. In order to simplify the functions in this post I avoid scoping altogether.

vlado's blog | add new comment
Home » blogs » vlado's blog

dikini.net

spreading confusion by accident since 1970