3 ms·
Transducers _can be_ parallelized (TODO) but some transducer implementations do contain state, like `take` and therefore cannot be parallelized. The big thing
by cfeduke 12y ago
Transducers _can be_ parallelized (TODO) but some transducer implementations do contain state, like `take` and therefore cannot be parallelized.
The big thing is no intermediate results.
- seanmcdirmid 12y agoSo transducers are like .Net/LINQ enumerables?
- Skinney 12y agoNah, Clojure seqs are more like .NET/LINQ enumerables. Functions that work over seqs/enumerables return a new seq/enumerable. From what I understand, and I'm sure I am wrong, a transducer receives and transforms a value, and may call the next transducer with the transformed value. The nice thing is that a transducer does not create intermediate results (a seq/enumerable), and that it doesn't make any assumptions on the underlying datastructure. So you can, for instance, send a value through a transducer and directly place it in a list, instead of creating a set of enumerables and then call .ToList on that. Since transducers can work with any value, you also aren't tied to enumerables. So transducers should be a little more universal and performant than enumerables.
- icefox 12y agoA contrived example in C#/LINQ Enumerable.Range(1, 100) .Where(n => n % 2 == 0) .Select(n => n * 2) .ToList(); And as a transducer it could looks something like this? sequence( Enumerable.Range(1, 100), compose( filter(n => n %2 == 0), map(x => x + 1) ) ).ToList(); On the linq side it would create only 2 enumerable objects (one for where and select) and the ToList would result in a copy the object pointer as it was passing through each enumerable. For the transducer example rather than having 2 enumerable's we would have 2 transducer objects? I absolutely understand the case where a language's map/filter/reduce/etc results in a whole new list, but for the above case the performance/memory overhead improvement doesn't see that huge and really minor. The fact that it removes the overhead of having to support IEnumerable and as you mentioned is only dealing with functions is what seems like a win. At first I was thinking that plain old LINQ is also more readable, but my contrived c# transducer example doesn't look that bad in the end. Am I incorrect on any of this?
- ajanuary 12y agoWith Linq you can't really create an object/function that describes the transformation that should happen. I start with an enumerable, describe how to transform /that/ enumerable, and in the end have something that describes a transformation applied to a particular initial data. I can't do anything with it but laziy read the transformed values for the original input. With transducers I can describe a transformation that should happen to /some/ reducable input, and in the end have something that represents just the transformation. I. An then apply that to any reducable input I have. [edit] Your example becomes: var incrementedEvens = compose( filter(n => n %2 == 0), map(x => x + 1) ); transduce(Enumerable.range(0, 100), incrementEvens); var lowerAlph = compose( filter(x => Character.isAlpha(x)), map(x => x.ToLowercase()) ); System.in.setTransducer(lowerAlpha); You can really do that in Linq.
- YuriNiyazov 12y agoIf you watch the first Rich Hickey Transducers talk, he shows that some transducers (the ones that rely in the underlying reduce implementation that uses fork/join and assumes that reducing the collection is associative) are already parallelized. I agree with you regarding `take`
- cfeduke 12y agoIIRC from yesterday's talk he was explaining that these will be easy to parallelize, and its slated for 1.7. I had thought they were already parallel myself until I saw the talk; and possibly some of them are, but the item is still Open. http://dev.clojure.org/jira/browse/CLJ-1553 http://dev.clojure.org/jira/browse/CLJ-1553
- YuriNiyazov 12y agoI was just talking about the "reduce fold" being already parallel.
- nickik 12y agoThe big thing is not even that, the big thing is that you can seperate your logic from the data that you want to process. So instead of (map inc [1 2 3 4]) you can do (def inc-transducer (map inc)) and then use that for any datastructures, channels or whatever other transducer context people come up with. To be sure, you would not do that with (map inc) but if you have more logic, you could.