Wednesday, September 30, 2009

APL jot dot in scheme and php

So I am implementing APL in php... As a matter of practice of course I am prototyping things. The ultimate scheme yields an oo/fluent expression approach but immediately here is how I would implement jot dot in php and scheme:

PHP:

function jotDot($fun, $v1, $v2) {
$result = array();
foreach($v1 as $x) {
$result[$x] = array();
foreach($v2 as $y) $result[$x][$y] = $fun($x, $y);
}
return $result;
}


Scheme:

(define (mapcar func list)
(if (null? list) '()
(cons (func (car list)) (mapcar func (cdr list)))))

(define (jotDot func v1 v2)
(mapcar (lambda (x) (mapcar (lambda (y) (func x y)) v2)) v1))


I am not going to lie - the scheme is definitely more elegant but it is not as readable as the php. I think that is sort of interesting. Maybe mapcar is not the right abstraction for the job and there is a better approach. Oh yeah in APL:

The eventual "fluent expression" APL->php interpreted code to do something like calculating a times table up to 12 would look like:

$V = APL()->indexGenerator(12);
$V->jotDot('times', $V);

Monday, July 27, 2009

more php5 musing

Whilst in normal php-land another livable library for me is going to be my phparrayplus leveraging anon functions.


$results = StaticClass::methodReturnsArray($arg)->eachPair(function($i, $x){
return $x->lookMaNoTmpVars($i + 1);
});


In my opinion so much prettier than

$results = StaticClass::methodReturnsArray($arg);
foreach($results as $i=>$x){
$results[$i] = $x->lookMoCrappTastic($i + 1);
}

Monday, July 20, 2009

curry in php 5.3

Here is curry in php 5.3

function curry(){
$args = func_get_args();
$fn = array_shift($args);
return function() use(&$fn, &$args) {
$nargs = func_get_args();
foreach($nargs as $narg) $args[] = $narg;
return call_user_func_array($fn, $args);
};
}

$add20 = curry(function($a, $b){return $a + $b;}, 20);
echo $add20(5); #25

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: http://rayfd.wordpress.com/2007/05/06/y-combinator-for-dysfunctional-non-schemers/


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(
array_shift($args),
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));
$get_walter();
$set_walter(500);
}

etc. etc. etc.

Wednesday, June 24, 2009

recess framework and metacircularity

The collection space has been in the process of an overhaul for some time now in preparation for some huge structural and philosophical changes that we have in the pipeline. One of the biggest challenges has been committing to a framework for php. I have evaluated (and used for client projects etc.) zend, cake, codeigniter etc. and all of them fall short of making me feel like they are increasing my productivity rather than getting in my way as they weakly attempt to adhere to design patterns. I have been working on my pet framework in the background for some time but even that I would not want to commit to for a project of this magnitude as it bumps documentation up in priority for other developers to be able to be productive with out me guiding them through things.

So what then? Recess (http://www.recessframework.org/) has shown up and been the only framework in php that I've kept my eye on and been constantly more impressed rather than more disappointed when I start looking into the internals. Being a young project I feel it is an ideal candidate for a lot of the code generation and object modeling tools that I have been playing with for voltron. Once cspace is live (july 9th) I plan on formalizing a lot of the tools that have helped me with Recess - mainly the object browser/editor and metacircular parser. What does that mean? It means I can edit files in and editor or individual methods through a browser based object browser/editor and not have an issue. I have another approach for views which I may offer up but it seems like Recess has some cool stuff in store so I will wait and see. But for cspace I am going forward with our view approach (no html, s-expression format called LET).

Friday, December 19, 2008

templating dsl

So I am evaluating different ways of using my new "view adapter" templating engine. Sparing the details I would like to try out a few different versions of syntax. Straight php, s-expressions and then let/smalltalk.

#PHP
$layout = Array('border_layout',
'center' => 'this is the center',
'south' => Array('border_layout',
'north' => 'this is the north of the south',
'south' => 'this is the south of the south'),
'north' => Array('form', 'method'=>'POST', 'with'=>Array(
Array('input', 'name'=>'first_name', 'label'=>'First Name'),
Array('submit', 'value'=>'Save')));


One nice thing about the php approach is that I can combine integer indexed with associative indexed arrays thus Array('submit', 'value' => 'Save') becomes possible as opposed to Array('type' => 'submit', 'value' => 'Save'). Clearly the adapter has to know that [0] is the type and thus shift that off before rendering the rest of the component.

#LET
$layout = [border_layout
center:'this is the center'
south:[border_layout
north:'this is the north of the south'
south:'this is the south of the south']
north:[form method:post with:[
[input name:first_name label:'First Name]
[submit value:Save]]];

As let sits atop php the same combination of integer indexed and associative indexes applies here too. Clearly replacing => with : and dropping quotes around single word keys and value makes things nicer as does making the commas optional as lists are white space seperated. As a note the reason I am dropping quotes is that within let there are no constants unless they are class constants. Thus there would never be a time you "accidentally" used a constant instead of a key. Also [] is not used for indexes or pushing values onto array in LET as it is more "smalltalk esque" in that you use methods for all things. And the reason I am not using [$var|$body] for code blocks is that I am using {$var|$body} as they are not used in smalltalk and coming from c/php { } feels right to me to denote a block of code.

#S-EXPR
$layout = (border_layout
(center 'this is the center')
(south (border_layout
(north 'this is the north of the south')
(south 'this is the south of the south'))
(north (form method:post with:(
(input name:first_name label:'First Name')
(submit value:Save))))

S-expressions will always have a certain element of "balance" about them not afforded by any other syntax, next to let I prefer this for sure. Except this is not strictly "lisp"y in that I am using key:value pairs intead of :key value or (key value) groupings.

#JSON
$layout = {border_layout:{
center: 'this is the center',
south: {border_layout:{
north: 'this is the north of the south',
south: 'this is the south of the south'}},
north: {type:'form', method:'post', with:{
{type:'input', name:'first_name', label:'First Name'},
{type:'submit', value:'Save'}}};

Json is again consistent but there is no way of doing the {control, key:value} trick here except for maybe {submit:1, key:value} but that feels pretty hackish. Still at least you don't have to write Array() all over the place!

Saturday, December 13, 2008

nodes relating to nodes to relate to nodes

A design decision which I made early on was to have the simple concept of nodes which can relate to nodes to describe their very relation by more node relations. haha sound confusing? The main point of actually using a node itself to describe a relationship is for that reason exactly: to be able to store node content to describe that particular relationship. i.e. if you were to model a recipe perhaps you would want to give a more meaningful description of each ingredient in the recipe beyond just what the ingredient is and it's quantity. thus you end up with


apple pie (recipe)
-> (recipe ingredient) -> apple (fruit)
-> 1/2 cup (measurement)

-> (recipe ingredient) -> margarine (food)
-> 1 pound (weight)



I think that makes sense the trick is that each word in parentheses is indicating what type of node it is. The generalization of this relation is:


(recipe) -> (recipe ingredient) -> ((food) (measurement))


So there is a relation between recipe and recipe ingredient types. Then there are two more relations between recipe ingredient and food and measurement. You will notice that this means the relation is valid for anything descending from the specified type i.e. weight extends measurement and fruit extends food thus both beig valid relations.

Another example would be a "record"

(record) -> (pressing) -> ((format) (color) (pressing number) (number pressed))
-> (relased by) -> (band)


the point is that the structure of the node types is by nature hierarchical merely to allow the inheritence/cascading of relations. But the way the instances of nodes relate is not hierarchical at all in that any node can relate to any other node so long as the relation is established and in the main I think that is going to remain entirely open except for in the case of "system structures" i.e. want lists and "collection space collections".