Tuesday, 11 September 2012

Iterators


Recently I came across a situation where I need to iterate over multiple result sets. Since SPL has a decent collection of iterators I began my search there. So I came across the MultipleIterator thinking it would solve all my problems. It didn't.
The problem with the MultipleIterator is that it doesn't provide a continuous stream of elements of all the attached iterators, instead it 'groups' them. Per iteration you get an array of all n-th elements for all attached iterators.
Given the following piece of code:

<?php
$iter 
= new MultipleIterator();
$iter->attachIterator(new ArrayIterator(range(05)));
$iter->attachIterator(new ArrayIterator(range(1015)));

foreach (
$iter as $row) {
    
var_dump($row);
}


The output is:

array(2) {
  [0]=>
  int(0)
  [1]=>
  int(10)
}
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(11)
}
array(2) {
  [0]=>
  int(2)
  [1]=>
  int(12)
}
array(2) {
  [0]=>
  int(3)
  [1]=>
  int(13)
}
array(2) {
  [0]=>
  int(4)
  [1]=>
  int(14)
}
array(2) {
  [0]=>
  int(5)
  [1]=>
  int(15)
}

Not exactly what i want. And even worse, all iterators need to be of the same length. It just doesn't cover my use case where I simply want to group a bunch of iterators and interface with them as if it were a single one.

It seems the SPL doesn't provide a solution to my use case, so I wrote my own. This is the implementation I ended up with:

<?php 
class MultiIterator 
implements Iterator 
{
    
/**
     * Holds the stack of iterators
     * @var array
     */
    
protected $iterators = array();
    
/**
     * Holds the index to the current interator
     * @var integer
     */
    
protected $current_iterator_idx;
    
/**
     * Add a new iterator to the stack
     * @param Iterator $iterator
     */
    
public function appendIterator(Iterator $iterator)
    {
        
$this->iterators[] = $iterator;
    }
    
/**
     * Returns the currently used iterator
     * @return Iterator
     */
    
public function iterator()
    {
        return (isset(
$this->iterators[$this->current_iterator_idx])) ? $this->iterators[$this->current_iterator_idx] : false;
    }
    
/**
     * (non-PHPdoc)
     * @see Iterator::current()
     */
    
public function current()
    {
        return 
$this->iterator()->current();
    }
    
/**
     * (non-PHPdoc)
     * @see Iterator::next()
     */
    
public function next()
    {
        
//does nothing
        
return $this->iterator()->next();
    }
    
/**
     * (non-PHPdoc)
     * @see Iterator::key()
     */
    
public function key()
    {
        return 
$this->iterator()->key();
    }
    
/**
     * (non-PHPdoc)
     * @see Iterator::valid()
     */
    
public function valid()
    {
        if (!
count($this->iterators)) {
            return 
false;
        }
        
//check if current iterator is valid
        
$valid $this->iterator()->valid();
        if (
false === $valid) { //this iterator has dried up, try and find a new one
            //increment the index to find a new iterator
            
$this->current_iterator_idx++;

            
//now check if we have a new iterator
            
if (false !== $this->iterator()) {
                
//we have a new iterator, valid or not
                
return $this->iterator()->valid();
            } else {
                
//no more iterators
                
return false;
            }
        }
     
        
//apparantly, the current iterator is still valid
        
return $valid;
    }
    
/**
     * (non-PHPdoc)
     * @see Iterator::rewind()
     */
    
public function rewind()
    {
        
//reset state
        
$this->current_iterator_idx 0;
        
array_walk($this->iterators, function($iter) {
            
$iter->rewind();
        });
    }
}


With the expected usage and output:

<?php
$iter 
= new MultiIterator();
$iter->appendIterator(new ArrayIterator(range(06)));
$iter->appendIterator(new ArrayIterator(range(1015)));

foreach (
$iter as $row) {
    
var_dump($row);
}



int(0)
int(1)
int(2)
int(3)
int(4)
int(5)
int(6)
int(10)
int(11)
int(12)
int(13)
int(14)
int(15)

Problem solved.

Thursday, 2 February 2012

Currying vs. Partial Application

I am a longtime fan of functional programming. I came in contact with it through articles by Paul Graham and Joel Spolsky.

Since first class functions (or closures, anonymous functions, lambda functions) are possibly *the* cornerstone of functional programming, there wasn't much to do in the pre-5.3 days. The closest you'd get to closures was create_function(), which is awkward at best and non-functional at worst.
So now we have closures, which has its quirks, but is mostly functional I guess.

By the way, in the above paragraph I talk about closures, anonymous functions and lambda functions as being equal. I know there are subtle differences, but I think in the context of PHP they are negligible. I will usually use the term 'closure' or 'anonymous function', but they both refer to the same concept.

Now, on to the meat of this post. Currying vs. Partial Application. Two terms most programmers that know about functional languages have most likely heard about, but a lot of people get them mixed up or use them interchangeably.
I will first explain and demonstrate currying in the context of PHP, since this is the most misunderstood and, in my opinion, most useless of the two.

Currying
What is currying? From Wikipedia:
Currying is the technique of transforming a function that takes multiple arguments in such a way that it can be called as a chain of functions each with a single argument.
This is best explained using an example. Say we have a function that expects three arguments and returns the sum:

    
function sum3($x$y$z)
    {
        return 
$x $y $z;
    }


Now we need to create a function that returns a chain of functions that only accept a single argument.

    function curried_sum3($x)
    {
        return function (
$y) use ($x) {
            return function (
$z) use ($x$y) {
                return 
sum3 ($x$y$z);
            };
        };
    }



We would want to call it like this:

    $result curried_sum3(1)(2)(3);


Unfortunately, PHP won't let us. But if I'm not mistaken we get that functionality in PHP 5.4 as part of the (new Foo())->method() syntax. So we have to assign each step to a temporary variable.

    $f1 =  curried_sum3(1);
    
$f2 $f1(2);
    
$result $f2(3);


So this is currying. I honestly can't see a practical use for this in a language (and associated scope) like PHP. But I'd love to be proven wrong! If you can make an argument and use case where function currying wouldn't be as awkward as it seems, or even beneficial, please let me know in the comments.

Partial Application
Now comes the interesting bit: Partial Application. A technique that is oftentimes called currying, but it's actually a whole different animal. Per Wikipedia the definition of partial application is:
Partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.
Basically it is a technique to reduce the number of arguments to a function. If we build upon the sum3() function we have used earlier, we can fix the first argument to 1 and receive a new function that only requires two arguments:

    function partial_sum3($x)
    {
        return function(
$y$z) use($x) {
            return 
sum3($x$y$z);
        };
    }


The resulting function requires only two arguments: $y and $z. $x will be fixed as the argument passed to partial_sum3().

    //create the partial
    
$f1 partial_sum3(1);
    
//execute the partial with the two remaining arguments
    
$result $f1(23);

The problem with this situation is that it's not dynamic. What we want is a partial function generator. A function that expects a function and n number of arguments. Fortunately, now we can create something like that fairly easy:

    function partial($func$arg1 /**, rest*/)
    {
        
$args func_get_args();
        
$func array_shift($args);

        return function() use(
$func$args) {
            
$full_args array_merge($argsfunc_get_args());
            return 
call_user_func_array($func$full_args);
        };
    }


With this function we can create any partial we want:

    $f1 partial('sum3'12);
    
$result $f1(3);

We reduced the number of arguments to sum3() to only one.
A practical example of this could be to easily map an array of timestamps into nicely formatted date/time's:

    //array of timestamps
    
$timestamps = array(132537600013280544001330560000);
    
//create the date formatter by fixing the format and effectively removing the first argument
    
$date_formatter partial('date''Y-m-d H:i:s');
    
//map the timestamps to their nicely formatted counterparts
    
$datetimes array_map($date_formatter$timestamps);
    
var_dump($datetimes);
/**
Output:
array(3) {
  [0]=>
  string(19) "2012-01-01 01:00:00"
  [1]=>
  string(19) "2012-02-01 01:00:00"
  [2]=>
  string(19) "2012-03-01 01:00:00"
}
*/


I think this should pretty much cover the basics of currying and partial application and how it applies to PHP. I hope you enjoyed reading it as much as I enjoyed writing it.

Happy coding!