I was quite excited to see that php 5.4 was getting some sugar for array definitions. e.g. "array(1,2,3)" would finally become "[1,2,3]". I was also excited to see "array dereferencing" was fixed or accessing an array by index after it is returned from a function e.g. "func()[index]". However let us be clear in noting that this does NOT mean it has attained the flexibility one would anticipate. For instance you can not immediately access an array after declaring it such as "['name' => 'peter', 'age' => 30]['age']" results in a syntax error. Of course you could combine both of the new features to do "func(['name' => 'peter', 'age' => 03])['age']" - which probably covers the majority of ways in which it would be used. The other issue I have is the inability to access a function upon it's return from function application e.g. "func(1)(2)" will result in a syntax error. This is problematic for higher order techniques that benefit dynamic languages.
Why would anyone want features such as those I have outlined above? People designing "in language" domain specific languages benefit greatly from such flexibility. Particularly in a language which already limits facilities for creating such mythical beasts.
That being said - I will gladly let go of my personal hack for passing in name/value pairs to a function which I have lovingly/jokingly referred to as "appositive expressions" e.g. "func('key', 'value', 'key2', 'value2')" can now become "func(['key' => 'value', 'key2' => 'value2'])". It is not surprising at all that php finally gets this feature as ruby finally bit the bullet and now accepts the json esque ":" in place of the "hash rocket =>". '
I should mention that the addition of "traits" will go miles in cleaning up some otherwise convoluted approaches to attaining mixins in php! I am very excited to see how this is utilized by the different frameworks.
Common PHP
An exploration of the limits of PHP
Wednesday, August 17, 2011
Tuesday, June 7, 2011
smalltalk, apl, soy lisp, and higher order operands
APL, Smalltalk, Lisp. The holy trinity of programming languages. In this post I aim to better explain the Soy Lisp syntax which allows for all three to coexist.
Consider first the ability to drop parens when an expression is terminated via ".":
This creates an immediate problem w/ disambiguation when dealing with arguments, well thankfully we do not lose the ability to return to s-expressions when required e.g.:
What else can we glean from smalltalk? Perhaps the ability to cascade via ;, e.g.:
In prior posts I have shown my preference for "square lambdas" e.g: [x | x y]. So I will not continue to rant about the benefits here. The last thing I will borrow from smalltalk is keyword constants (whilst keeping lisp keywords) e.g.:
The above assumes func is a higher order function which knows how to dispatch keyword selector arguments, which is essentially how I would implement a smalltalk esque language on top of soy.
I think it is clear that functional programming in lisp can benefit from the smalltalk syntax whilst not losing the power of macro expansion and s-expressions.
This brings us to APL the other language I have toyed w/ writing interpreters for. The real crux of apl is working with higher order operators. e.g. reduce which takes on the left hand an operator which it then uses to reduce a set of numbers on the right. In traditional prefix notation this would end up like:
Which works just fine because + is a higher order operator which knows if its first argument is another operator it should return a function which does a + reduction.
In soy the latter works because numbers are "higher order operands" which can consume operators and return functions which consume more operators/operands as expected. Stay tuned for a web repl for those interested in playing with this. Bare in mind that both forms in all of these examples work with in the same environment as this is all syntactic sugar! Lisp wins again.
Consider first the ability to drop parens when an expression is terminated via ".":
(func arg1 arg2)
//becomes
func arg1 arg2.
This creates an immediate problem w/ disambiguation when dealing with arguments, well thankfully we do not lose the ability to return to s-expressions when required e.g.:
func arg1 (func2 arg1 arg2).
What else can we glean from smalltalk? Perhaps the ability to cascade via ;, e.g.:
(((func arg1) arg2) arg3)
//becomes
func arg1; arg2; arg3.
In prior posts I have shown my preference for "square lambdas" e.g: [x | x y]. So I will not continue to rant about the benefits here. The last thing I will borrow from smalltalk is keyword constants (whilst keeping lisp keywords) e.g.:
(func :keyword1 var1 :keyword2 (lambda (x) (x :says 'peter))
//becomes
func keyword1: var1 keyword2: [x | x says: 'peter].
The above assumes func is a higher order function which knows how to dispatch keyword selector arguments, which is essentially how I would implement a smalltalk esque language on top of soy.
I think it is clear that functional programming in lisp can benefit from the smalltalk syntax whilst not losing the power of macro expansion and s-expressions.
This brings us to APL the other language I have toyed w/ writing interpreters for. The real crux of apl is working with higher order operators. e.g. reduce which takes on the left hand an operator which it then uses to reduce a set of numbers on the right. In traditional prefix notation this would end up like:
((/ +) 1 2 3 4)
//not bad but noisier than
+ / 1 2 3 4.
//which becomes
(+ / 1 2 3 4)
Which works just fine because + is a higher order operator which knows if its first argument is another operator it should return a function which does a + reduction.
(- (+ 5 5) 5)
//becomes
5 + 5 - 5.
In soy the latter works because numbers are "higher order operands" which can consume operators and return functions which consume more operators/operands as expected. Stay tuned for a web repl for those interested in playing with this. Bare in mind that both forms in all of these examples work with in the same environment as this is all syntactic sugar! Lisp wins again.
Labels:
apl,
higher order operands,
lisp,
smalltalk,
soy
Friday, May 27, 2011
Keyword Functions in PHP
So, as spurned by a comment on hacker news relating to the lack of ability for keyword arguments in php I figured I would expound more upon the Phutility library, in particular the Func module.
Check it out:
If this is at all interesting to you and you'd like to use it or contribute, the source and tests are all up on github.
Check it out:
#say you have a function (perhaps defined by you, perhaps not)
namespace SomeNamespace;
use Phutility\Func;
function testFunc($name, $eyes, $hair = 'blonde', $age = 0, $weight = 200, $goatFace = 'definitely') {
return array(
'name' => $name,
'eyes' => $eyes,
'hair' => $hair,
'age' => $age,
'weight' => $weight,
'goatFace' => $goatFace);
}
#if you want a keyword wrapper for it:
$testFuncWrapper = Func::keyword('\SomeNamespace\testFunc');
$result = $testFuncWrapper(
age, 30,
name, 'peter'
);
/*would yield a $result of
array(
'name' => 'peter',
'eyes' => 'blue',
'hair' => 'blonde',
'age' => 30,
'weight' => 1200,
'goatFace' => 'definitely'
)
*/
# If you want to not have a variable func you would need to do something like:
function TestFuncWrapper() {
static $wrapper;
if(!$wrapper) {
$wrapper = Func::keyword('\SomeNamespace\TestFunc');
}
return call_user_func_array($wrapper, func_get_args());
}
#a little gnarlier but this is the price we pay to call it like:
$result = TestFuncWrapper(
goatFace, 'NoWay'
);
#oops this would yield an exception because name and age are required!
If this is at all interesting to you and you'd like to use it or contribute, the source and tests are all up on github.
Wednesday, May 25, 2011
On unit testing
When ever I am confronted with a problem with a code base, my first reaction is: "wtfutfts" meaning "where's the fucking unit tests for that shit". No unit tests? Now you know your first move in providing resolution.
Alternative s-expression syntax for Soy Lisp
Soy is the name of my lisp dialect (previously called lisphp, and before that phlisp). This is quite a radical departure from standard lisp s-expression but not so far as to, say have infix notation or "sweet expressions". Rather this is a simple inverse of s-expression e.g.:
Becomes:
Your first question should be, "but wait! what about homoiconicity and the ability to have quasiquote macro definitions!?". I'm glad you asked, I have two proposals. 1) allow for a s-expression macro syntax, 2) allow for quasiquote to start with an atom:
You may have noticed the other drawback with this syntax is that it makes having macros which handle sublists a tad more difficult. As any atom followed by (, applies the atom to the arguments inside of the parens. This can be resolved by using rest args for forms which anticipate the last expression to be treated as a lambda. Also Soy allows for [ | ] lambda forms and { } vector/dicts. So it is also possible that would resolve any ambiguities.
One of my major ambitions with this is to have a very simple syntax for exploring alternative object models, similar to my previous post about an alternative object model for javascript.
I really dig how close this comes to snythesizing what I love about smalltalk w/ lisp w/o really forsaking either.
One of the real "wins" with this is when you have function returning functions .. n you don't end up w/ a massive amount of nesting.
I think the latter reads in a much more obvious "left to right" fashion.
(if (predicate arg1 arg2)
(thenFunc arg2)
(elseFunc arg3))
Becomes:
if(predicate(arg1 arg2)
thenFunc(arg2)
elseFunc(arg3))
Your first question should be, "but wait! what about homoiconicity and the ability to have quasiquote macro definitions!?". I'm glad you asked, I have two proposals. 1) allow for a s-expression macro syntax, 2) allow for quasiquote to start with an atom:
defmacro(eat-apple person number-of-apples
`person-eat(,person 'apple ,number-of-apples))
You may have noticed the other drawback with this syntax is that it makes having macros which handle sublists a tad more difficult. As any atom followed by (, applies the atom to the arguments inside of the parens. This can be resolved by using rest args for forms which anticipate the last expression to be treated as a lambda. Also Soy allows for [ | ] lambda forms and { } vector/dicts. So it is also possible that would resolve any ambiguities.
One of my major ambitions with this is to have a very simple syntax for exploring alternative object models, similar to my previous post about an alternative object model for javascript.
;simple keyword selector
some-object(set-first-name: 'peter and-last-name: 'jenkum)
;chaining
some-object(some-keyword: arg1 selector: arg2)
(chained-selector: arg3 takes-closure: [ a | a(message: arg4)])
(another-chained-selector: [_(anon-var)])
I really dig how close this comes to snythesizing what I love about smalltalk w/ lisp w/o really forsaking either.
One of the real "wins" with this is when you have function returning functions .. n you don't end up w/ a massive amount of nesting.
(def adder [x | [y | [z | + x y z]]])
(((adder 6) 7) 8)
def(adder [x | [y | [z | +(x y z)]]])
adder(6)(7)(8)
I think the latter reads in a much more obvious "left to right" fashion.
Monday, May 23, 2011
simple keyword message selectors for javascript
As I have been messing with alternative object systems for php one of the ones I came up with was ab(using) the __invoke magic method to take a keyword argument list and find a given selector based upon it. I realized this could be done in an even more trivial manner in javascript using the object syntax and returning a new object w/ the dispatch mechanism rather than "return this".
To see it live: jsfiddle running the above
var Klasses = {
'Person': {
'selectorPart1:selectorPart2': function(a, b) {
console.log('called with ' + a + ' and ' + b);
return obj(this);
},
'subSelector': function(a) {
console.log('subselector with:' + a + ' for ' + this.name);
return obj(this);
},
'get': function(field) {
console.log(this.name + ' over-ride of get with ' + field);
}
},
'*': {
'get': function(field) {
if(this[field]) {
return this[field]
} else {
throw new Exception('No field ' + field);
}
}
}
};
var obj = function(self) {
return function(selector) {
var sel = [];
var args = [];
$.each(selector, function(k, v) {
sel.push(k);
args.push(v);
});
var selectorName = sel.join(':');
var message = false;
if(Klasses[self.klass][selectorName]) {
message = Klasses[self.klass][selectorName];
}
else if(Klasses['*'][selectorName]) {
message = Klasses['*'][selectorName];
}
if(message) {
return message.apply(self, args);
}
};
}
var guy = obj({klass: 'Person', name: 'peter'});
guy({selectorPart1: 'apple', selectorPart2: 'candy'})
({subSelector: 'rotten'})
var otherGuy = obj({klass: 'Person', name: 'samuel'})({subSelector: 'cotton'})
console.log(otherGuy({get: 'name'}))
To see it live: jsfiddle running the above
Friday, May 20, 2011
On Phutility
Phutility is a collection of tools which I utilize in many of my other projects. For example the Node class is utilized by both covenants (sql builder) and also phmop (meta object protocol). Today though I am going to be discussing some of the work that I have been doing in Func to lay the framework for "higher order object oriented programming" with phmop. To give you an idea of what I am driving at, consider:
There are a few things we can cleanup. Firstly lets create a function "method" which wraps up simple functions which utilize an accessor which is the same as their internal name. Then lets utilize a higher order function "Func\options" which returns a function which has the last param defined as an options hash to clean things up:
But we can go further by creation an optionsMethod which wraps up the need for the explicit Func\options call. Also we can have it pass a param which gives us back a std class for options rather than an array.
For the sake of completeness let me show off another way this could be defined more explicitly taking advantage of Func\keyword which evaluates a closure and then returns a function which responds to an appositive style call:
As you can see this allows us to pass the params in any order we please (which to be fair our Func\options implementation does as well but packaged into an $options var). So now we will skip to step 3 of what a keywordMethod would look like in use:
I think this makes clear why both a meta object protocol and higher order functions are so awesome when they can play together. Rather than having only inheritence, interfaces, or even mixins, as the tool for making things more elegant we can easily add new features to our language with simple function composition.
defineClass('Person',
slot('someMethod', function($self) {
$args = func_get_args();
$self = array_shift($args);
$options = appos($args);
if($self->{$options[ifField]} == $options[isValue]) {
$self->call($options[callMethod], $options[withValues]);
}
})->accessor('someMethod'));
$person = new Person;
$person->someMethod(
ifField, 'age',
isValue, 30,
callMethod, 'someMethod2',
withValues, array(300));
There are a few things we can cleanup. Firstly lets create a function "method" which wraps up simple functions which utilize an accessor which is the same as their internal name. Then lets utilize a higher order function "Func\options" which returns a function which has the last param defined as an options hash to clean things up:
defineClass('Person',
method('someMethod', Func\options(function($self, $options) {
if($self->{$options[ifField]} == $options[isValue]) {
$self->call($options[callMethod], $options[withValues]);}})));
But we can go further by creation an optionsMethod which wraps up the need for the explicit Func\options call. Also we can have it pass a param which gives us back a std class for options rather than an array.
defineClass('Person',
optionsMethod('someMethod', function($self, $options) {
if($self->{$options->ifField} == $options->isValue) {
$self->call($options->callMethod, $options->withValues);}}));
For the sake of completeness let me show off another way this could be defined more explicitly taking advantage of Func\keyword which evaluates a closure and then returns a function which responds to an appositive style call:
$keywordFunc = Func\keyword(function($age, $name, $color) {
return array('age' => $age, 'name' => $name, 'color' => $color);
});
print_r($keywordFunc(
age, 30,
color, 'blue',
name, 'peter'));
array(
'age' => 30,
'name' => 'peter',
'color' => 'blue');
As you can see this allows us to pass the params in any order we please (which to be fair our Func\options implementation does as well but packaged into an $options var). So now we will skip to step 3 of what a keywordMethod would look like in use:
defineClass('Person',
keywordMethod('someMethod',
function($self, $ifField, $isValue, $callMethod, $withValues) {
if($self->$ifField == $isValue) {
$self->call($callMethod, $withValues);}}));
$person = new Person;
$person->someMethod(
ifField, 'age',
isValue, 30,
callMethod, 'someMethod2',
withValues, array(300));
I think this makes clear why both a meta object protocol and higher order functions are so awesome when they can play together. Rather than having only inheritence, interfaces, or even mixins, as the tool for making things more elegant we can easily add new features to our language with simple function composition.
Subscribe to:
Posts (Atom)