Transducers are a type of reducing function that take in a reducing function and give back another reducing function. They allow you to compose functions together in a chain or pipeline structure to quickly, easily and efficiently transform data. In PHP, we have the mtdowling/transducers library, built off the basis of the idea of Clojure's transducer library.
20. Phone Tree as Transducer
use Transducers as t;â¨
â¨
$employees = (new EmployeeService)->getAllEmployees();â¨
$getNonManagerPhones = tcomp(â¨
tfilter(function ($employee) { â¨
return ! $employee->isManager(); â¨
}),â¨
tmap(function ($employee) { â¨
return $employee->getPhoneNumber(); â¨
})â¨
);â¨
$numbers = tto_array($getNonManagerPhones, $employees);
21. The Data
Name Number Manager
Bob 303-555-1212 Yes
Sue 303-555-1234 No
Barb 303-555-1111 No
Spongebob 303-555-1001 Yes
Arnold 303-555-1313 No
22. Collection Data Pipeline
Name Number Manager
Bob 303-555-1212 Yes
Sue 303-555-1234 No
Barb 303-555-1111 No
Spongebob 303-555-1001 Yes
Arnold 303-555-1313 No
Filter
Name Number Manager
Sue 303-555-1234 No
Barb 303-555-1111 No
Arnold 303-555-1313 No
Map
Number
303-555-1234
303-555-1111
303-555-1313
23. Transducer Data Flow
Name Number Manager
Bob 303-555-1212 Yes
Sue 303-555-1234 No
Barb 303-555-1111 No
Spongebob 303-555-1001 Yes
Arnold 303-555-1313 No
Number
303-555-1234
303-555-1111
303-555-1313
ďŹlter
map
NO
24. Transducer Data Sources
⢠Anything that you can use foreach on
⢠Arrays
⢠Iterators
⢠Traversables
⢠Generators
27. A Bigger Example
⢠Incoming TSV, but should be CSV
⢠Date format is wrong
⢠Names are not capitalized
⢠We need days from or until birthdate, for reasons
28. Transformer
use transducers as t;â¨
/* SNIP Definition of the functions used below */
$transformer = tcomp(â¨
tdrop(1), // Get rid of the headerâ¨
tmap($convertToArray), // Turn TSV to Arrayâ¨
tmap($convertToDate), // Change to DateTimeImmutable Objectâ¨
tmap($addDaysFromBirthday), // Date mathâ¨
tmap($fixDateFormat), // Format DateTimeImmutable
// to Y-m-d string
$fixNames, // Capitalize namesâ¨
);
35. Function to Build a Function
// Function to return a functionâ¨
$ucField = function($field) {â¨
return function ($row) use ($field) {â¨
$row[$field] = ucfirst($row[$field]);â¨
return $row;â¨
};â¨
};
36. Functionally Functional
$mungeField = function ($field, $munger) {â¨
return function ($row) use ($field, $munger) {â¨
$row[$field] = $munger($row[$field]);â¨
return $row;â¨
};â¨
};
38. Revisit Transformer
use transducers as t;â¨
/* SNIP Definition of the functions used below */
$transformer = tcomp(â¨
tdrop(1), // Get rid of the headerâ¨
tmap($convertToArray), // Turn TSV to Arrayâ¨
tmap($convertToDate), // Change to DateTimeImmutable Objectâ¨
tmap($addDaysFromBirthday), // Date mathâ¨
tmap($fixDateFormat), // Format DateTimeImmutable
// to Y-m-d string
$fixNames, // Capitalize namesâ¨
);
45. Included Transducer
Functions
⢠map($f) - Apply $f function to each value in a
collection
⢠ďŹlter($predicate) - If predicate returns true, retain
the value, otherwise discard
⢠remove($predicate) - Removes items that satisfy the
predicate function
⢠cat() - Concatenates items from nested lists
46. More Included Functions
⢠partition($size) - Splits the source into arrays of the
speciďŹed size
⢠partition_by($predicate) - Splits input into arrays
when value returned by $predicate changes
⢠take($n) - Takes $n items from the collection
⢠take_while($predicate) - Takes items from the
collection while the $predicate is true
47. Even Moar!
⢠take_nth($n) - Takes every $n values from the
collection
⢠drop($n) - Drops $n items from the start of a
sequence
⢠drop_while($predicate) - Drops items from the
collection as long as $predicate returns true
⢠replace(array $map) - Replaces values in the
sequence according to the $map
48. Ermegerhd, even more?!
⢠keep($f) - Keeps items when $f does not
return null
⢠keep_indexed($f) - Returns the non-null
results of calling $f($index, $value)
⢠dedupe - Removes values that are the same
as the previous value in an ordered
sequence
⢠interpose($separator) - Adds the separator
between each value in a sequence
49. Last list, I promise
⢠tap($interceptor) - "Taps" into the chain, in
order to do something with the intermediate
result. Does not change the sequence
⢠compact() - Trims out all "falsey" values from
the sequence
⢠words() - Splits input into words
⢠lines() - Splits input by lines
50. Transducers
⢠Compose powerful data processing functions
⢠Interact with streams of data
⢠Easy to understand
⢠Simple to test