Am Freitag, 17. Oktober 2014 04:02:52 UTC+2 schrieb Daniel James:
>
> Hi Michael,
>
> I’m glad you are in favor of this change; however, and with tongue firmly 
> in cheek, you’ve taken a beautiful thing and corrupted it, which I can’t 
> condone. ;)
>
> Let me offer an explanation as to why I half-jokingly say this.
>
> From what you’ve said, your “group-by-style transducer” is going to have 
> the following form:
>
> (fn [rf]
>   ([] {})
>   ...)
>
> Irrespective of the rest of its implementation, it’s a function that 
> transforms a reducing function into another reducing function, but it is 
> most certainly *not* a transducer—a necessary, but not a sufficient 
> condition.
>
> Before I make an appeal to types, let me build some intuition by borrowing 
> the analogy that Rich Hickey made in his talk at Strange Loop. He was 
> saying that he wanted to give instructions to the baggage handlers about 
> how to handle the baggage, without having to say anything about whether the 
> baggage arrived on a trolley or by conveyor belt. By returning {} in the 
> 0-arity, you are effectively saying, “No, it’s definitely going to be on a 
> trolley!”.
>

Hi Daniel,

I'm not quite sure if your trolley-analogy is viable here (but see below).  
Please note that I'm working
within a reduce scenario: a "conveyor belt" is moving data to the reducing 
function, and once the
conveyor stops a single value is left behind -- the final result of the 
reducing fn.

The grouping I am using does two things within this metaphor: in the one 
direction, it splits one conveyor
into n independent conveyors; in the other direction, it combines n reduced 
results again into a single result.

In code it looks like this:

(defn group-by-xf [f]
  (fn [rf]
    (let [init (rf)]
      (fn
        ([] {})
        ([result]
           (reduce-kv (fn [acc k v] (assoc acc k (rf v)))
                      {} result))
        ([result input]
           (let [k (f input)
                 group-result (get result k init)]
             (assoc result k (rf group-result input))))))))


[...] 

>
>
> If I call
>
> (into [] xform (range 5))
>
> (transduce xform + 0 (range 5))
>
> I expect a vector and an integer to pop out, respectively, and I’m going 
> to be sorely disappointed if a map pops out instead!
>
>
In this case you might prefer to write something like (transduce xform 
(comp group-by-xf +) ...) instead
of (transduce (comp xform group-by-xf) + ...) . If I had used the first 
variant, then I would not have stumbled
over the default init value of transduce at all.  Mh.  Seen this way, I 
only have to adjust my code accordingly and can
continue to use the default init as it is.  Thank you for this insight!
 

> By the way, please, please, don’t read this as a polemic. I just want to 
> be precise about the issue, and I am certainly sympathetic to “While 
> experimenting I…”!
>

No offense taken.  I do understand that beauty is always in the eye of the 
beholder.

Using the grouping function above I was able to take a gnarly aggregation 
function (basically a multi
level update-in plus a transformation on the leaves when done) and turn it 
into a sequence of
group-by-xf plus a much simpler reducing fn.  This is very beautiful to me 
;-)

-- Michael


-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to