-
-
Save softprops/5981830 to your computer and use it in GitHub Desktop.
case class Counter(x: Int = 0) | |
/** A type class for combining types through aggregation */ | |
sealed trait Aggregate[As, Elem] { | |
def apply(el: Elem): As | |
def empty: As | |
def apply(as: As, el: Elem): As | |
} | |
/** A companion to Aggregate exposing a single method, `values` | |
* which produces an arbirary type from the aggregation of elements | |
*/ | |
object Aggregate { | |
implicit object IntSetAggregate extends Aggregate[Set[Int], Int] { | |
def empty = Set.empty[Int] | |
def apply(el: Int) = Set(el) | |
def apply(as: Set[Int], el: Int) = as + el | |
} | |
implicit object IntCounterAggregate extends Aggregate[Counter, Int] { | |
def empty = Counter() | |
def apply(el: Int) = Counter(el) | |
def apply(as: Counter, el: Int) = as.copy(x = as.x + el) | |
} | |
/** @param pairs is a set of keys and values | |
* @return a Map keyed on the pairs initial value with a value of As | |
* representing some arbitrary aggregation | |
*/ | |
def values[K, V, As] | |
(pairs: Iterable[(K, V)]) | |
(implicit aggr: Aggregate[As, V]) = | |
(Map.empty[K, As].withDefaultValue(aggr.empty) /: pairs) { | |
case (m, (k, v)) => m.updated(k, aggr(m(k), v)) | |
} | |
} | |
val in = Set((1, 2), (1, 3), (3, 4)) | |
Aggregate.values[Int, Int, Set[Int]](in) // Map(1 -> Set(2, 3), 3 -> Set(4)) | |
Aggregate.values[Int, Int, Counter](in) // Map(1 -> Counter(5), 3 -> Counter(4)) |
Thanks @jedws. This was an example of the typeclass pattern used as an example to teach a co worker of just that. I know what monoids are :) They weren't needed to explain the typeclass pattern. using a monoid as an example of how to use typeclasses means a i may also have to explain what monoids were which could have been helpful but would also have made the lesson more complicated than I intended. I find it most effective to introduce concepts one at time when teaching others. Adding complexity sometimes muddys the main idea of what what you are trying to teach. A followup on how a concept called monoids can be implemented in terms of typeclasses may have been something like your example. It wasn't necessary to explain monoids in order to explain typeclasses here.
You basically have a less flexible version of Monoid:
then for Int addition:
and say for String append:
Now you can compose, abstracting over the inner Monoid:
And use it: