Skip to content

Instantly share code, notes, and snippets.

@talebzeghmi
Created November 8, 2015 02:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save talebzeghmi/94653a9a6e5b6eb285f4 to your computer and use it in GitHub Desktop.
Save talebzeghmi/94653a9a6e5b6eb285f4 to your computer and use it in GitHub Desktop.
Type class without scala macros https://github.com/malcolmgreaves/abstract_data
import scala.language.higherKinds
import scala.reflect.ClassTag
import scala.language.implicitConversions
trait Data[D[_]] extends Serializable {
def map[A, B: ClassTag](d: D[A])(f: A => B): D[B]
def flatMap[A, B: ClassTag](d: D[A])(f: A => Iterable[B]): D[B]
def filter[A](d: D[A])(f: A => Boolean): D[A]
def groupByKey[K: ClassTag, V: ClassTag](d: D[(K, V)]): D[(K, Iterable[V])]
def reduceByKey[K: ClassTag, V: ClassTag](d: D[(K, V)])(op: (V, V) => V): D[(K, V)]
def union[A](d1: D[A], d2: D[A]): D[A]
}
object Data {
object Implicits {
implicit class InfixOps[D[_]: Data, A](data: D[A]) {
lazy val typeClassInstance: Data[D] = implicitly[Data[D]]
def map[B: ClassTag](f: A => B): D[B] =
typeClassInstance.map(data)(f)
def flatMap[B: ClassTag](f: A => Iterable[B]): D[B] =
typeClassInstance.flatMap(data)(f)
def filter(f: A => Boolean): D[A] =
typeClassInstance.filter(data)(f)
def union(d2: D[A]): D[A] =
typeClassInstance.union(data, d2)
}
implicit class InfixPairOps[D[_]: Data, K: ClassTag, V: ClassTag](data: D[(K, V)]) {
lazy val typeClassInstance = implicitly[Data[D]]
def groupByKey(): D[(K, Iterable[V])] =
typeClassInstance.groupByKey(data)
def reduceByKey(op: (V, V) => V): D[(K, V)] =
typeClassInstance.reduceByKey(data)(op)
}
}
}
import Data.Implicits.InfixOps
def fooData[D[_]: Data](data: D[Boolean]): D[Int]=
data.map(d => if (d) 1 else 0)
implicit val seqData = new Data[Seq] {
println("seqData")
override def map[A, B: ClassTag](d: Seq[A])(f: (A) => B): Seq[B] = d.map(f)
override def flatMap[A, B: ClassTag](d: Seq[A])(f: (A) => Iterable[B]): Seq[B] = d.flatMap(f)
override def filter[A](d: Seq[A])(f: (A) => Boolean): Seq[A] = d.filter(f)
override def reduceByKey[K: ClassTag, V: ClassTag](d: Seq[(K, V)])(op: (V, V) => V): Seq[(K, V)] =
groupByKeyHelper(d)
.map { case (k, vs) => (k, vs.reduce((a,b) => op(a, b))) }
override def groupByKey[K: ClassTag, V: ClassTag](d: Seq[(K, V)]): Seq[(K, Iterable[V])] =
groupByKeyHelper(d)
override def union[A](d1: Seq[A], d2: Seq[A]): Seq[A] =
d1.union(d2)
private def groupByKeyHelper[A, K](d: Seq[(K, A)]): Seq[(K, Iterable[A])] =
d.groupBy(_._1).toSeq.map { case (k, a) => (k, a.map(_._2).toIterable) }
}
fooData(Seq(true, false, true, true))
fooData(Seq(true, false, true, true))
fooData(Seq(true, false, true, true))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment