The idea of declaratively describing transformations of data seems very exciting to me. I haven't experienced anything that lives up to the excitement though.<p>I feel a bit underwhelmed by these examples. Seems a bit to imperative, an enhancement of underscore. I want the declarations of how data representations relate to each other to be separate from the "how" in how to transform from one format to another. Probably something inspired by lenses (1). "Lenses are the XPath of _everything_." (2).<p>(1) - <a href="https://www.fpcomplete.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial" rel="nofollow">https://www.fpcomplete.com/school/to-infinity-and-beyond/pic...</a><p>(2) - <a href="https://twitter.com/steveklabnik/status/463748643141349376" rel="nofollow">https://twitter.com/steveklabnik/status/463748643141349376</a><p>edit: Relevant HN comment about using Lenses for reaching into data objects: <a href="https://news.ycombinator.com/item?id=7704504" rel="nofollow">https://news.ycombinator.com/item?id=7704504</a>
Just by glancing quickly over it it's difficult to draw big conclusions but, while the concept certainly feels promising I'm not sure about API - transduce require 4 parameters and it feels like you really need to know what happens inside to make use of it (that append function feels especially off). But maybe it's just me not being able to switch to functional way and it's simply a matter of spending some time with it (and do some serious work with it).
Reading that article inspired me to write a little generic recursion library. The idea is that you'd write a 'map' function for each recursive data structure and then generate recursive functions from non-recursive functions using 'induction' and 'coinduction'.<p><pre><code> // induction : ((t (Fix t), Fix t -> r) -> t r, t r -> r) -> Fix t -> r
function induction(map, f) {
// g : Fix t -> r
function g(x) {
return f(map(x.unfold(), g));
};
return g;
};
// coinduction : ((t s, s -> Fix t) -> t (Fix t), s -> t s) -> s -> Fix t
function coinduction(map, f) {
// g : s -> Fix t
function g(s) {
return {
unfold: function() {
return map(f(s), g);
}
};
};
return g;
};
// fold : t (Fix t) -> Fix t
function fold(w) {
return {
unfold: function() { return w; }
};
};</code></pre>
For some reason (maybe environmental factors), I understood this article much better than Rich Hickeys initial post. However, I suppose I should now go back and re-read it.<p>Thanks for the great library and explanation.
I think the name "transducers" is a little unfortunate only in that it sounds very foreign to most coders, leading the concept to potentially be ignored. Don't let the name "transducers" or the relation to Clojure scare you off; you don't have to know either thing to understand how transducers can be useful.