type classes 101 - classification beyond inheritance

42
Type classes 101 Classification beyond inheritance Alexey Raga

Upload: alexey-raga

Post on 16-Aug-2015

187 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Type classes 101 - classification beyond inheritance

Type classes 101Classification beyond inheritance

Alexey Raga

Page 2: Type classes 101 - classification beyond inheritance

String

Int

List[Boolean]

case class Name(value: String)

case class Age(value: Int)

case class Person(name: Name, age: Age)

case class Gang(leader: Person, members: List[Person])

Types classify data

Page 3: Type classes 101 - classification beyond inheritance

String

Int

List[Boolean]

case class Name(value: String)

case class Age(value: Int)

case class Person(name: Name, age: Age)

case class Gang(leader: Person, members: List[Person])

Types classify data

Page 4: Type classes 101 - classification beyond inheritance

public class Person implements ISerialisable{ public String name; public String address;

...}

public void saveToDisk(ISerialisable obj) { … }

Types classify data

Page 5: Type classes 101 - classification beyond inheritance

Types classify data

public class Person implements ISerialisable, IJsonSerialisable, IXmlSerialisable, IPrettyPrint{ public String name; public String address;

...}

Page 6: Type classes 101 - classification beyond inheritance

Expression problem

trait Exprcase class Lit(value: Int) extends Exprcase class Add(x: Expr, y: Expr) extends Expr

val expr = Add(Lit(15), Lit(6))

Page 7: Type classes 101 - classification beyond inheritance

Expression problem

● Operation extensionadd new operations: eval, prettyPrint, etc.

● Data extensionadd new expressions: Mul, Pow, Neg, ec.

● Static type safetyno isInstanceOf / asInstanceOf

Page 8: Type classes 101 - classification beyond inheritance

Expression problem

● Operation extensionadd new operations: eval, prettyPrint, etc.

● Data extensionadd new expressions: Mul, Pow, Neg, ec.

● Static type safetyno isInstanceOf / asInstanceOf

Page 9: Type classes 101 - classification beyond inheritance

Expression problem

trait Expr { def eval: Int def print: String}

case class Lit(value: Int) extends Expr { def eval = ??? def print = ???}

case class Add(x: Expr, y: Expr) extends Expr { def eval = ??? def print = ???}

Page 10: Type classes 101 - classification beyond inheritance

Expression problem

trait Expr { def eval: Int = this match { case Lit => ??? case Add => ??? } def print: String = this match { case Lit => ??? case Add => ??? }}

case class Lit(value: Int) extends Exprcase class Add(x: Expr, y: Expr) extends Expr

Page 11: Type classes 101 - classification beyond inheritance

We can do better

Page 12: Type classes 101 - classification beyond inheritance

Classification

Plants Animals

?

Page 13: Type classes 101 - classification beyond inheritance

Classification

Fungi

Page 14: Type classes 101 - classification beyond inheritance

Classification

Page 15: Type classes 101 - classification beyond inheritance

Classification

Page 16: Type classes 101 - classification beyond inheritance

Classification

Page 17: Type classes 101 - classification beyond inheritance

Classifying types

trait Serialisable[A] { def serialise(obj: A) : Array[Byte]}

object PersonSerialisable extends Serialisable[Person] { def serialise(obj: Person): Array[Byte] = ???}

def saveToDisk[A](obj: A, ser: Serialisable[A]) = { val data = ser.serialise(obj) ???}

saveToDisk(Person("john", 99), PersonSerialisable)

Page 18: Type classes 101 - classification beyond inheritance

Type classes classify types

trait Serialisable[A] { def serialise(obj: A) : Array[Byte]}

implicit object PersonSerialisable extends Serialisable[Person] { def serialise(obj: Person): Array[Byte] = ???}

def saveToDisk[A](obj: A)(implicit ser: Serialisable[A]) = { val data = ser.serialise(obj) ???}

saveToDisk(Person("john", 99))

Page 19: Type classes 101 - classification beyond inheritance

Type classes classify types

// already defined in Scala// def implicitly[T](implicit e: T) = e

def saveToDisk[A: Serialisable](obj: A) = { val ser = implicitly[Serialisable[A]] val data = ser.serialise(obj) ...}

saveToDisk(Person("john", 99))

Page 20: Type classes 101 - classification beyond inheritance

Testimony ;)

Page 21: Type classes 101 - classification beyond inheritance
Page 22: Type classes 101 - classification beyond inheritance
Page 23: Type classes 101 - classification beyond inheritance

Just saying...import serialisation.json._//import serialisation.csv._//import serialisation.xml._

def saveToDisk[A](obj: A)(implicit ser: Serialisable[A]) = { val data = ser.serialise(obj) ???}

saveToDisk(Person("john", 99))

Page 24: Type classes 101 - classification beyond inheritance

Type classes in Scalatrait Ordering[T] { def compare(x : T, y : T) : Int def lteq(x : T, y : T) : Boolean = compare(x, y) <= 0 def gteq(x : T, y : T) : Boolean = compare(x, y) => 0 ...}

trait Numeric[T] extends Ordering[T] { def plus(x : T, y : T) : T def minus(x : T, y : T) : T def negate(x : T) : T ...}

Page 25: Type classes 101 - classification beyond inheritance

Type classes in Scalatrait Ordering[T] { def compare(x : T, y : T) : Int def lteq(x : T, y : T) : Boolean = compare(x, y) <= 0 def gteq(x : T, y : T) : Boolean = compare(x, y) => 0}

trait Numeric[T] extends Ordering[T] { def plus(x : T, y : T) : T def minus(x : T, y : T) : T def negate(x : T) : T}

trait TraversableOnce[+A] { def sum[B >: A](implicit num : scala.Numeric[B]) : B = ??? def min[B >: A](implicit cmp : scala.Ordering[B]) : A = ??? def max[B >: A](implicit cmp : scala.Ordering[B]) : A = ???}

Page 26: Type classes 101 - classification beyond inheritance

Type classes in Scalatrait Ordering[T] { def compare(x : T, y : T) : Int def lteq(x : T, y : T) : Boolean = compare(x, y) <= 0 def gteq(x : T, y : T) : Boolean = compare(x, y) => 0}

trait Numeric[T] extends Ordering[T] { def plus(x : T, y : T) : T def minus(x : T, y : T) : T def negate(x : T) : T}

trait TraversableOnce[+A] { def sum[B >: A](implicit num : scala.Numeric[B]) : B = ??? def min[B >: A](implicit cmp : scala.Ordering[B]) : A = ??? def max[B >: A](implicit cmp : scala.Ordering[B]) : A = ???}

val sum = List(1,2,3).sumval min = List(1,2,3).min

Page 27: Type classes 101 - classification beyond inheritance

Type classes in Scalaztrait Equal[A] { def equal(a1 : A, a2 : A) : Boolean}

trait Show[A] { def shows(a : A) : String}

trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B]}

trait Semigroup[A] { def append(a1 : A, a2 : => A) : A}

trait Monoid[A] extends Semigroup[A] { def zero : A}

Page 28: Type classes 101 - classification beyond inheritance

Deriving proofs

//tuple of Equals is also an Equalimplicit def tuple2Equal[A: Equal, B: Equal]: Equal[(A, B)] = new Equal[(A, B)] { def equal(a1: (A, B), a2: (A, B)) : Boolean = a1._1 === a2._1 && a1._2 === a2._2 }

//tuple of Semigroups is also a Semigroupimplicit def tuple2Semigroup[A: Semigroup, B: Semigroup]: Semigroup[(A, B)] = { new Semigroup[(A, B)] { def append(p1: (A, B), p2: => (A, B)) = ((p1._1 |+| p2._1), (p1._2 |+| p2._2)) }}

Page 29: Type classes 101 - classification beyond inheritance
Page 30: Type classes 101 - classification beyond inheritance

Expression problempackage ep

trait Exprcase class Lit(value: Int) extends Exprcase class Add[A <: Expr, B <: Expr](x: A, y: B) extends Expr

Page 31: Type classes 101 - classification beyond inheritance

Expression problem

● Operation extensionadd new operations: eval, prettyPrint, etc.

● Data extensionadd new expressions: Mul, Pow, Neg, ec.

● Static type safetyno isInstanceOf / asInstanceOf

Page 32: Type classes 101 - classification beyond inheritance

Expression problempackage ep.evaluateimport ep._

trait Eval[A <: Expr] { def eval(expr: A) : Int}

object Eval { def evaluate[A <: Expr](expr: A)(implicit evA: Eval[A]) = evA.eval(expr)

implicit object LitEval extends Eval[Lit] { def eval(expr: Lit) = expr.value }

implicit def addEval[A <: Expr, B <: Expr](implicit evA: Eval[A], evB: Eval[B]) = { new Eval[Add[A, B]] { def eval(expr: Add[A, B]) = evA.eval(expr.x) + evB.eval(expr.y) } }}

Page 33: Type classes 101 - classification beyond inheritance

Expression problempackage ep import evaluate._

Eval.evaluate( Add(Lit(15), Lit(6)) ) === 21

Page 34: Type classes 101 - classification beyond inheritance

Expression problempackage ep.expressionsimport ep._import evaluate._

case class Mul[A <: Expr, B <: Expr](x: A, y: B) extends Expr

object Mul {

implicit def mulEval[A <: Expr, B <: Expr](implicit evA: Eval[A], evB: Eval[B]) = { new Eval[Mul[A, B]] { def eval(expr: Mul[A, B]) = evA.eval(expr.x) * evB.eval(expr.y) } }

}

Page 35: Type classes 101 - classification beyond inheritance

Expression problemimport evaluate._import expressions._

Eval.evaluate( Mul(Lit(2), Add(Lit(15), Lit(6))) ) === 42

Page 36: Type classes 101 - classification beyond inheritance

Expression problempackage ep.operationsimport ep._import ep.expressions._

trait PPrint[A <: Expr] { def print(expr: A) : String}

object PPrint { def prettyPrint[A <: Expr](expr: A)(implicit pa: PPrint[A]) = pa.print(expr)

implicit object LitPrint extends PPrint[Lit] { def print(expr: Lit) = expr.value.toString }

implicit def mulPrint[A <: Expr, B <: Expr](implicit pA: PPrint[A], pB: PPrint[B]) = { new PPrint[Mul[A, B]] { def print(expr: Mul[A, B]) = pA.print(expr.x) + " * " + pB.print(expr.y) } }

Page 37: Type classes 101 - classification beyond inheritance

Expression problemimport expressions._import operations._import evaluate._

PPrint.prettyPrint( Mul(Lit(2), Add(Lit(15), Lit(6))) ) === "2 * (15 + 6) = 42"

Page 38: Type classes 101 - classification beyond inheritance

Expression problem

● Operation extensionadd new operations: eval, prettyPrint, etc.

● Data extensionadd new expressions: Mul, Pow, Neg, ec.

● Static type safetyno isInstanceOf / asInstanceOf

Page 39: Type classes 101 - classification beyond inheritance

● Add behaviours retroactivelyNo need to change existing data types

● Solution to the Expression problemOperation and data extension with static type safety

● Different kinds of operations“instance” (A => String), “factory” (String => A), etc.

Page 40: Type classes 101 - classification beyond inheritance
Page 41: Type classes 101 - classification beyond inheritance
Page 42: Type classes 101 - classification beyond inheritance

What about us?

Isn't it enough?

No we're not in paradise

This is who we are

This is what we've got

No it's not our paradise