3 ms·
I'm not seeing anything that looks like a reducing function transformer there. That all looks like variants of ordinary function composition, currying and parti
by richhickey 12y ago
I'm not seeing anything that looks like a reducing function transformer there. That all looks like variants of ordinary function composition, currying and partial application. Is there someplace that shows 'operator forms' acting as functions with this signature: (x->a->x)->(x->a->x)?
- taliesinb 12y agoWL doesn't yet have a laziness/streaming/reducing framework, but the prototype we're working on uses 'operator forms' like Select, Map, GroupBy and so on in the way you describe. I don't think the exact details are the same, because our operators don't actually evaluate to transformers (they remain totally symbolic). Rather, the conversion of composed operators to an actual reducer pipeline happens lazily 'at the right time', which I think will make optimization a bit easier to express.
- jamii 12y agoSo if I understand correctly, you would arrive at a symbolic expression like (->> (map f) (map g) x) and directly rewrite it to (->> (map (f . g)) x), rather than having to manipulate the resulting data-structures?
- deleted 12y ago[deleted]
- taliesinb 12y agoYeah, it's pretty easy to turn Map[#^2&] /* Select[PrimeQ] /* Select[OddQ] into Select[OddQ[#] && PrimeQ[#]&] /* Map[#^2&] and so on via rules that look like: Select[s1_] /* Select[s2_] :> Select[s1[#] && s2[#]&] Map[f_ ? SideEffectFreeQ] /* s_Select :> s /* Map[f] Map[Extract[p_Integer | p_Key]] :> Extract[{All, p}] I'm already doing a bunch of that for Dataset. But in reality you need to move to a DSL for complex enough rules, and then Clojure and WL will be on the same footing (Clojure even a bit stronger, maybe, WL doesn't really have a proper macro system). Does Clojure core do or allow for any of that kind of optimization already?
- malisper 12y agoI don't know about Clojure, but Common Lisp provides something called Compiler Macros[0]. They basically allow the programmer to define two versions of a procedure. One that is a macro, and one that is an actual procedure. The macro will expand only at compile time (it can also specify to call the procedure instead of expanding), and the procedure will be called only at run time. I suggest you look at [0] for some examples of how it is possible to optimize something as simple as squaring a number. [0] http://clhs.lisp.se/Body/m_define.htm http://clhs.lisp.se/Body/m_define.htm
- scythe 12y agoIt appears that the operator forms he's talking about are things like Select[EvenQ], which would become "transducers" if I could do something like: even_selector = Select[EvenQ] incrementor = Map[Inc] decrementor = Map[Dec] even_incremented_selector = incrementor * even_selector (????) odd_selector = even_incremented_selector * decrementor even_selector[{1,2,3,4,5,6,7}] => {2,4,6} even_incremented_selector[{1,2,3,4,5,6,7}] => {2,4,6,8} odd_selector[{1,2,3,4,5,6,7}] => {1,3,5,7} However I'm not entirely sure I've understood things correctly, I just stared at it for a while and need to get back to work... (edit: HN does _not_ like formatting)
- taliesinb 12y agoNo, because all that is required for operator forms to do what you write is just ordinary function application. Which they already do just fine. Rich is talking about something deeper, in which operators like filter become transformers that themselves operate on stateful processors (reducers) to produce new stateful processors that have incorporated the action described by the original operator.