```package scalaz

import Scalaz._
/**
* A Reducer[C,M] is a Monoid[M] that maps
* values of type C through `unit` to values of type M. A C-Reducer may also
* supply operations which tack on another C to an existing 'Monoid' M on the left
* or right. These specialized reductions may be more efficient in some scenarios
* and are used when appropriate by a 'Generator'. The names 'cons' and 'snoc' work
* by analogy to the synonymous operations in the list monoid.
*
* Minimal definition: 'unit' or 'snoc'
*
* Based on a Haskell library by Edward Kmett
**/
abstract class Reducer[C, M](implicit mm: Monoid[M]) {
val monoid = mm
def unit(c: C): M = snoc(mzero, c)
def snoc(m: M, c: C): M = m |+| unit(c)
def cons(c: C, m: M): M = unit(c) |+| m

final def &&&[N](r: Reducer[C, N]): Reducer[C, (M, N)] = {
implicit val n = r.monoid
new Reducer[C, (M, N)] {
override def unit(x: C) = (Reducer.this.unit(x), r.unit(x))
override def snoc(p: (M, N), x: C) = (Reducer.this.snoc(p._1, x), r.snoc(p._2, x))
override def cons(x: C, p: (M, N)) = (Reducer.this.cons(x, p._1), r.cons(x, p._2))
}
}
}

trait Reducers {
import Scalaz._
implicit def ReducerMonoid[C, M](r: Reducer[C, M]) = r.monoid

/** Construct a Reducer with the given unit function and monoid **/
def Reducer[C, M: Monoid](unit: C => M) = {
val u = unit
new Reducer[C, M] {
override def unit(c: C) = u(c)
}
}

def Reducer[M: Monoid]: Reducer[M, M] = Reducer(x => x)

def ListReducer[C] = new Reducer[C, List[C]] {
override def unit(c: C) = List(c)
override def cons(c: C, cs: List[C]) = c :: cs
}

def StreamReducer[C] = new Reducer[C, Stream[C]] {
override def unit(c: C) = Stream(c)
override def cons(c: C, cs: Stream[C]) = c #:: cs
}

def UnitReducer[C]: Reducer[C, Unit] = Reducer((c: C) => ())

def AnyReducer: Reducer[Boolean, Boolean] = Reducer(x => x)

def AllReducer: Reducer[Boolean, BooleanConjunction] = Reducer(x => conjunction(x))

def EndoReducer[A]: Reducer[A => A, Endo[A]] = Reducer(EndoTo(_))

def DualReducer[A: Monoid]: Reducer[A, Dual[A]] = Reducer(_.dual)

def IntProductReducer: Reducer[Int, IntMultiplication] = Reducer(x => multiplication(x))

def CharProductReducer: Reducer[Char, CharMultiplication] = Reducer(x => multiplication(x))

def ByteProductReducer: Reducer[Byte, ByteMultiplication] = Reducer(x => multiplication(x))

def LongProductReducer: Reducer[Long, LongMultiplication] = Reducer(x => multiplication(x))

def ShortProductReducer: Reducer[Short, ShortMultiplication] = Reducer(x => multiplication(x))

def BigIntProductReducer: Reducer[BigInt, BigIntMultiplication] = Reducer((x: BigInt) => multiplication(x))

import java.math.BigInteger
def BigIntegerProductReducer: Reducer[BigInteger, BigIntegerMultiplication] = Reducer((x: BigInteger) => multiplication(x))

def FirstReducer[A]: Reducer[A, FirstOption[A]] = Reducer(x => Some(x))
def FirstOptionReducer[A]: Reducer[Option[A], FirstOption[A]] = Reducer(x => x)

def LastReducer[A]: Reducer[A, LastOption[A]] = Reducer(x => Some(x))
def LastOptionReducer[A]: Reducer[Option[A], LastOption[A]] = Reducer(x => x)

}

```