When you look at the implementation, is should be apparent why `seqop`

and `combop`

have to be different.

The idea is that it specifically groups into an optimal a tree structure as possible.

`((1+2)+(3+4)) + ((5+6)+(7+8))`

or

`(("a".length + "ab".length)+("abc".length+"abcd".length)) + (("abcde".length+"abcdef".length)+("abcdefg".length+"abcdefgh".length))`

You are right,my description of lazy was misleading. What I should have said, is that I want to delay the calls to `combop`

as long as possible, and dereference the return values of `seqop`

as early as possible. The implementation maintains a stack of at most log_2(n) values returned from `seqop`

. (`n`

being the length of the input list/set/etc)

```
def treeAggregate[A, B](objects: TraversableOnce[A], init: B, seqop: A => B, combop: (B, B) => B): B = {
def consumeStack(stack: List[(Int, B)]): List[(Int, B)] = {
stack match {
case (i, a1) :: (j, a2) :: tail if i == j => consumeStack((i + 1, combop(a1, a2)) :: tail)
case _ => stack
}
}
val stack = objects.foldLeft((1, init) :: Nil) { (stack: List[(Int, B)], ob: A) =>
(1, seqop(ob)) :: consumeStack(stack)
}
// there may be up to log_2 of objects.size many pairs left on the stack
// but there is not precisely 0 such pairs on the stack.
assert(stack != Nil)
stack.tail.map(_._2).fold(stack.head._2)(combop)
}
```