Transducers.php
Composable algorithmic transformations in PHP (mostly a toy and unsupported)
Install / Use
/learn @mtdowling/Transducers.phpREADME
=============== transducers-php
.. image:: https://badges.gitter.im/Join Chat.svg :target: https://gitter.im/mtdowling/transducers.php?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
Transducers <http://clojure.org/transducers>_ are composable algorithmic
transformations. They are independent from the context of their input and
output sources and specify only the essence of the transformation in terms of
an individual element. Because transducers are decoupled from input or output
sources, they can be used in many different processes - collections, streams,
channels, observables, etc. Transducers compose directly, without awareness of
input or creation of intermediate aggregates.
For more information about Clojure transducers and transducer semantics see the
introductory blog post <http://blog.cognitect.com/blog/2014/8/6/transducers-are-coming>_
and this video <https://www.youtube.com/watch?v=6mTbuzafcII>_.
You can transduce anything that you can iterate over in a foreach-loop (e.g.,
arrays, \Iterator, Traversable, Generator, etc.). Transducers can
be applied eagerly using transduce(), into(), to_array(),
to_assoc(), to_string(); and lazily using to_iter(),
xform(), or by applying a transducer stream filter.
::
composer.phar require mtdowling/transducers
Defining Transformations With Transducers
Transducers compose with ordinary function composition. A transducer performs
its operation before deciding whether and how many times to call the transducer
it wraps. You can easily compose transducers to create transducer pipelines.
The recommended way to compose transducers is with the transducers\comp()
function:
.. code-block:: php
use Transducers as t;
$xf = t\comp(
t\drop(2),
t\map(function ($x) { return $x + 1; }),
t\filter(function ($x) { return $x % 2; }),
t\take(3)
);
The above composed transducer is a function that creates a pipeline for
transforming data: it skips the first two elements of a collection,
adds 1 to each value, filters out even numbers, then takes 3 elements from the
collection. This new transformation function can be used with various
transducer application functions, including xform().
.. code-block:: php
$data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$result = t\xform($data, $xf);
// Contains: [5, 7, 9]
Transducers
Transducers are functions that return a function that accept a reducing
function array $xf and return a new reducing function array that wraps the
provided $xf.
Here's how to create a transducer that adds $n to each value:
.. code-block:: php
$inc = function ($n = 1) {
// Return a function that accepts a reducing function array $xf.
return function (array $xf) use ($n) {
// Return a new reducing function array that wraps $xf.
return [
'init' => $xf['init'],
'result' => $xf['result'],
'step' => function ($result, $input) use ($xf, $n) {
return $xf['step']($result, $input + $n);
}
];
}
};
$result = t\xform([1, 2, 3], $inc(1));
// Contains: 2, 3, 4
.. _reducing-link:
Reducing Function Array
Reducing function arrays are PHP associative arrays that contain a 'init', 'step', and 'result' key that maps to a function.
+--------+-------------------------+------------------------------------------+
| key | arguments | Description |
+========+=========================+==========================================+
| init | none | Invoked to initialize a transducer. This |
| | | function should call the 'init' function |
| | | on the nested reducing function array |
| | | $xf, which will eventually call out |
| | | to the transducing process. This function|
| | | is only called when an initial value is |
| | | not provided while transducing. |
+--------+-------------------------+------------------------------------------+
| step | $result, $input | This is a standard reduction function |
| | | but it is expected to call the |
| | | $xf['step'] function 0 or more |
| | | times as appropriate in the transducer. |
| | | For example, filter will choose |
| | | (based on the predicate) whether to call |
| | | $xf or not. map will always call |
| | | it exactly once. cat may call it |
| | | many times depending on the inputs. |
+--------+-------------------------+------------------------------------------+
| result | $result | Some processes will not end, but for |
| | | those that do (like transduce), the |
| | | 'result' function is used to produce |
| | | a final value and/or flush state. This |
| | | function must call the $xf['result'] |
| | | function exactly once. |
+--------+-------------------------+------------------------------------------+
Using Transducers
Transducers can be used in any number of ways. This library provides several methods that can be used to apply transducers.
transduce()
``function transduce(callable $xf, array $step, $coll, $init = null)``
Transform and reduce $coll by applying $xf($step)['step'] to each value.
- ``callable $xf``: Transducer function to apply.
- ``array $step``: Transformer array that has 'init', 'result', and 'step' keys
that map to a callable.
- ``$coll``: Data to transform. Can be an array, iterator, or PHP stream
resource.
- ``$init``: Optional first initialization value of the reduction. If this
value is not provided, the ``$step['init']()`` function will be called to
provide a default value.
.. code-block:: php
use Transducers as t;
$data = [[1, 2], [3, 4]];
$xf = t\comp(
t\flatten(),
t\filter(function ($value) { return $value % 2; }),
);
$result = t\transduce($xf, t\array_reducer(), $data);
// Contains: [1, 3]
When using this function, you can use any of the built-in reducing function
arrays as the ``$step`` argument:
- ``transducers\array_reducer()``: Creates a reducing function array that
appends values to an array.
.. code-block:: php
$data = [[1, 2], [3, 4]];
$result = t\transduce(t\flatten(), t\array_reducer(), $data);
// Results contains [1, 2, 3, 4]
- ``transducers\stream_reducer()``: Creates a reducing function array that
writes values to a stream resource. If no ``$init`` value is provided when
transducing then a PHP temp stream will be used.
.. code-block:: php
$data = [[1, 2], [3, 4]];
$result = t\transduce(t\flatten(), t\stream_reducer(), $data);
fseek($result, 0);
echo stream_get_contents($result);
// Outputs: 1234
- ``transducers\string_reducer()``: Creates a reducing function array that
concatenates each value to a string.
.. code-block:: php
$xf = t\flatten();
// use an optional joiner on the string reducer.
$reducer = t\string_reducer('|');
$data = [[1, 2], [3, 4]];
$result = t\transduce($xf, $reducer, $data);
// Result is '1|2|3|4'
- ``transducers\assoc_reducer()``: Creates a reducing function array that adds
key value pairs to an associative array. Each value must be an array that
contains the array key in the first element and the array value in the second
element.
- ``transducers\create_reducer()``: Convenience function that can be used to
quickly create reducing function arrays. The first and only required argument
is a step function that takes the accumulated result and the new value and
returns a single result. The next, optional, argument is the init function
that takes no arguments an returns an initialized result. The next, optional,
argument is the result function which takes a single result argument and is
expected to return a final result.
.. code-block:: php
$result = t\transduce(
t\flatten(),
t\create_reducer(function ($r, $x) { return $r + $x; }),
[[1, 2], [3, 4]]
);
// Result is equal to 10
- ``transducers\operator_reducer()``: Creates a reducing function array that
uses the provided infix operator to reduce the collection (i.e.,
$result <operator> $input). Supports: '.', '+', '-', '*', and '/' operators.
.. code-block:: php
$result = t\transduce(
t\flatten()
t\operator_reducer('+'),
[[1, 2], [[3], 4]]
);
// Result is equal to 10
xform()
~~~~~~~
``function xform($coll, callable $xf)``
Returns the same data type passed in as ``$coll`` with ``$xf`` applied.
``xform()`` using the following logic when returning values:
- ``array``: Returns an array using the provided array.
- ``associative array``: Turn the provided array into an indexed array, meaning
that each value passed to the ``step`` reduce function is an array where
the first element is the key and the second element is the value. When
completed, ``xform()`` returns an associative array.
- ``\Iterator``: Returns an iterator in which ``$xf`` is applied lazily.
- ``resource``: Reads single bytes from the p
