PHPでlazy map

いまいち使いどころが見つからないけどPHPでlazy map書いてみた。
通常のmap(PHPだとarray_map)は、与えられたリストのすべてに関数を適用したリストを返すが、lazy mapでは実際にイテレータから値を取り出す時に初めて関数を適用する。

<?php

class LazyMap implements Iterator
{
    protected $iterator, $callback;
    
    function __construct($seq, $callback)
    {
        if (is_array($seq)) $this->iterator = new ArrayIterator($seq);
        elseif ($seq instanceof Iterator) $this->iterator = $seq;
        elseif ($seq instanceof IteratorAggregate) $this->iterator = $seq->getIterator();
        else throw new InvalidArgumentException;
        
        if (!is_callable($callback)) throw new InvalidArgumentException;
        
        $this->callback = $callback;
    }
    
    function current()
    {
        return call_user_func($this->callback, $this->iterator->current());
    }
    
    function next()
    {
        $this->iterator->next();
    }
    
    function valid()
    {
        return $this->iterator->valid();
    }
    
    function key()
    {
        return $this->iterator->key();
    }
    
    function rewind()
    {
        $this->iterator->rewind();
    }
}

使ってみる

<?php

function hoge($val) 
{
    echo "called\n";
    return $val * $val; 
}

$seq = array(1, 2, 3, 4, 5);

// 通常のmap
foreach (array_map('hoge', $seq) as $elt) {
    echo "{$elt}\n";
}
echo "\n";

// lazy map
foreach (new LazyMap($seq, 'hoge') as $elt) {
    echo "{$elt}\n";
}

結果

called
called
called
called
called
1
4
9
16
25

called
1
called
4
called
9
called
16
called
25

通常のmapが最初に全ての要素に関数を適用するのとは違い、lazy mapでは実際に値を取り出すまで関数の適用を遅延させていることが分かる。