scala types of types @ lambda days

91
Scala ’s Types of Types Konrad 'ktoso' Malawski Lambda Days 2014 @ Kraków bg = game @ http://www.swordandsworcery.com/

Upload: konrad-malawski

Post on 10-May-2015

2.131 views

Category:

Technology


4 download

DESCRIPTION

Talk from LambdaDays 2014 in Krakow. The talk focuses on some of Scala's more prominent types. Video available here: https://vimeo.com/92620078

TRANSCRIPT

Page 1: Scala Types of Types @ Lambda Days

Scala’s Types of Types

Konrad 'ktoso' Malawski Lambda Days 2014 @ Krakówbg = game @ http://www.swordandsworcery.com/

Page 2: Scala Types of Types @ Lambda Days

_ @

Konrad `@ktosopl` Malawski

geecon.org Java.pl / KrakowScala.pl

sckrk.com / meetup.com/Paper-Cup @ London GDGKrakow.pl

meetup.com/Lambda-Lounge-Krakow

Page 3: Scala Types of Types @ Lambda Days

Types

Page 4: Scala Types of Types @ Lambda Days

Types“Implementation is an implementation detail.” ~ ktoso

Page 5: Scala Types of Types @ Lambda Days

Types in Scala

Page 6: Scala Types of Types @ Lambda Days

Types in Scala

Page 7: Scala Types of Types @ Lambda Days

Types in Scala

class Robot!class Human ! !val human: Human = new Human!val roman: Human = new Robot!!!!!!!

Types are: !

static

error: type mismatch;! found : Robot! required: Human! val robot: Human = new Robot! ^

Page 8: Scala Types of Types @ Lambda Days

Types in Scala

var two = 2!two = "two"!!

Types are: !

static strong error: type mismatch;!

found : String("two")! required: Int! two = "two"! ^

Page 9: Scala Types of Types @ Lambda Days

Types in Scala

val n = 2!n.getClass.toString == "int"!!!!!

Types are: !

static strong

inferred !

class Human!val p = new Human!p.getClass.toString == "class Human"

Page 10: Scala Types of Types @ Lambda Days

Types in Scala

Types are: !

static strong

inferred annotated after :

!! ! def add(a: Int, b: Int): Int!

! val n: Int = 2

Page 11: Scala Types of Types @ Lambda Days

Types with Traits

Page 12: Scala Types of Types @ Lambda Days

Types with Traits

Traits are: !

interfaces !

trait HasName { ! def name: String!}!!!

class Human extends HasName {! def name = ""!}

class Human(val name: String) ! extends HasName!

implementation:

Page 13: Scala Types of Types @ Lambda Days

Types with Traits

Traits are: !

interfaces with implementation

!trait HasName { def name = "name" }!!object Human extends HasName!!Human.name == "name"!

Page 14: Scala Types of Types @ Lambda Days

Types with Traits

Traits are: !

interfaces with implementation

can be “mixed in”

trait Robot!trait Humanoid!trait Lasers!!object X extends Robot ! with Humanoid! with Lasers!!

Multiple inheritance panic?!

Page 15: Scala Types of Types @ Lambda Days

Type linearization

object X extends Robot ! with Humanoid! with Lasers

trait Robot extends Lasers!trait Humanoid!trait Lasers

// type linearization:!X Robot Humanoid Lasers // reverse!X Lasers Humanoid Robot!! ! // expand!X Lasers Humanoid Robot Lasers // right-keep-unique!X Lasers Humanoid Robot Lasers!X Humanoid Robot Lasers // add common!X Humanoid Robot Lasers Object Any

Page 16: Scala Types of Types @ Lambda Days

Type linearization

// don’t trust me, trust the compiler:!import scala.reflect.runtime.universe._!typeOf[X.type].baseClasses.map(_.name).mkString(“ extends ")!!// output:!X extends Humanoid ! extends Robot extends Lasers ! extends Object extends Any!

trait Robot extends Lasers!trait Humanoid!trait Lasers

object X extends Robot ! with Humanoid! with Lasers

Page 17: Scala Types of Types @ Lambda Days

Type linearization

trait Robot extends Lasers!trait Humanoid!trait Lasers

object X extends Humanoid! with Lasers! with Robot

// type linearization:!X Humanoid Lasers Robot // reverse!X Robot Lasers Humanoid!! ! // expand!X Robot Lasers Lasers Humanoid // right-keep-unique!X Robot Lasers Lasers Humanoid!X Robot Lasers Humanoid // add common!X Robot Lasers Humanoid Object Any

reordered slightly

Page 18: Scala Types of Types @ Lambda Days

Type linearization

// don’t trust me, trust the compiler:!import scala.reflect.runtime.universe._!typeOf[X.type].baseClasses.map(_.name).mkString(“ extends ")!!// output:!X extends Robot ! extends Lasers extends Humanoid! extends Object extends Any!

trait Robot extends Lasers!trait Humanoid!trait Lasers

object X extends Humanoid! with Lasers! with Robot

Page 19: Scala Types of Types @ Lambda Days

Type Refinement

Page 20: Scala Types of Types @ Lambda Days

Type Refinement

val human: Human = new Human {}!val roman: Human = new Robot!

trait Human!trait Robot

Page 21: Scala Types of Types @ Lambda Days

Type Refinement

val human: Human = new Human {}!val roman: Human = new Robot with Human!

Waaah! It’s a robot with human traits!

plain trait compositiontype refinement

trait Human!trait Robot

Page 22: Scala Types of Types @ Lambda Days

Compound Types

Page 23: Scala Types of Types @ Lambda Days

Compound Types

are intersections

of types !

trait Openable {! def open()! }! trait Closable {! def close()! }!!!!!

Page 24: Scala Types of Types @ Lambda Days

Compound Types

are intersections

!

trait Openable {! def open()! }! trait Closable {! def close()! }!!!!!

open() close()

Page 25: Scala Types of Types @ Lambda Days

Compound Types

are intersections

!

trait Openable {! def open()! }! trait Closable {! def close()! }!!!!! def openAndClose(it: Openable with Closable) {! it.open() ! it.close()! }

Page 26: Scala Types of Types @ Lambda Days

Compound Types

are intersections

!

trait Openable {! def open()! }! trait Closable {! def close()! }!!!!! def openAndClose(it: Openable with Closable) {! it.open() ! it.close()! }

Page 27: Scala Types of Types @ Lambda Days

Compound Types

this.type

def openAndClose(it: Openable with Closable) =! it.open().close()

trait Openable {! def open(): this.type! }! trait Closable {! def close()! }!!!!!

Page 28: Scala Types of Types @ Lambda Days

!

Type Parameters

Page 29: Scala Types of Types @ Lambda Days

!

Type Parameters [Type Variance]

Page 30: Scala Types of Types @ Lambda Days

!

Type Parameters [Type Variance] <: Type Bounds >:

Page 31: Scala Types of Types @ Lambda Days

Type Parameters

class C[T]

type parameter

type constructor

Page 32: Scala Types of Types @ Lambda Days

Type Variance

class C[T] // in-variant!class C[+T] // co-variant!class C[-T] // contra-variant!

Page 33: Scala Types of Types @ Lambda Days

Type Bounds (still variance)

class Parent!class Bottom extends Parent!!

!Type Bounds Parent >: Bottom // parent is “more” general!Bottom <: Parent // bottom is “less” general!Parent =:= Parent // parent is “equal” parent

Page 34: Scala Types of Types @ Lambda Days

Type Variance

class C[T] // in-variant

val x: C[Parent] = new C[Parent]!!val x: C[Parent] = new C[Bottom]!error: type mismatch; found: C[Bottom] required: C[Parent]!Note: Bottom <: Parent, but class C is invariant in type A.!You may wish to define A as +A instead. (SLS 4.5)!!val x: C[Bottom] = new C[Parent]!error: type mismatch; found: C[Parent] required: C[Bottom]!Note: Parent >: Bottom, but class C is invariant in type A.!You may wish to define A as -A instead. (SLS 4.5)!

Page 35: Scala Types of Types @ Lambda Days

Type Variance

class C[+T] // co-variant

val x: C[Parent] = new C[Parent]!!val x: C[Parent] = new C[Bottom]!!val x: C[Bottom] = new C[Parent]!error: type mismatch; found: C[Parent] required: C[Bottom]!!!

Page 36: Scala Types of Types @ Lambda Days

Type Variance

class C[-T] // contra-variant

val x: C[Parent] = new C[Parent]!!val x: C[Parent] = new C[Bottom]!error: type mismatch; found: C[Bottom] required: C[Parent]!!val x: C[Bottom] = new C[Parent]!!!

Page 37: Scala Types of Types @ Lambda Days

Structural Type

Page 38: Scala Types of Types @ Lambda Days

Structural Types

// a type!class Closeable {! def close()!}

=>// structural type!type Closeable = {! def close()!}

Page 39: Scala Types of Types @ Lambda Days

Structural TypesKinda’ like “duck typing”

def send(msg: String, box: {def receive(a: String)}) =! box receive msg

structural type

Page 40: Scala Types of Types @ Lambda Days

Structural Types

type MailBoxLike = { ! def receive(a: String)!}

def send(msg: String, box: MailboxLike) =! box receive msg

type alias

Page 41: Scala Types of Types @ Lambda Days

Structural Types

type MailBoxLike = { ! def receive(a: String)!}

def send(msg: String, box: MailboxLike) =! box receive msg

object Home { def receive(a: String) = ??? }!object Work { def receive(a: String) = ??? }

send("hello at home", Home)!send("hello at work", Work)

Page 42: Scala Types of Types @ Lambda Days

Type Member

Page 43: Scala Types of Types @ Lambda Days

Type Member

Same goal as Type Parameter

trait StringList! extends List[String] => trait StringList !

extends List {! type A = String!}

if List was using Type Members

if List was using Type Params

Page 44: Scala Types of Types @ Lambda Days

Type Member + Type Bound

Same as + / - variance

trait List {! type A!}

trait IntegerList extends NumbersList {! type A = Integer!}

trait NumbersList extends List {! type A <: Number!}

=>

trait FailList extends NumbersList {! type A = Human // Human is not <: Number!!}

Page 45: Scala Types of Types @ Lambda Days

Type Alias

Page 46: Scala Types of Types @ Lambda Days

Without Type Alias

object `bytes -> string` ! extends Builder[Array[Byte], String] {! ! def make(in: Array[Byte]): String = new String(in)! }!

“1st” and “2nd” type param ALL HOPE IS LOST!

Page 47: Scala Types of Types @ Lambda Days

Without Type Alias

object `bytes -> string` ! extends Builder[Array[Byte], String] {! ! def make(in: Array[Byte]): String = new String(in)! }!

“1st” and “2nd” type param Some meaning is lost!

Page 48: Scala Types of Types @ Lambda Days

Type Alias

From Type Parameter to Type Members

trait Builder[From, To] => trait Builder {! type From! type To! def make(in: From): To! }

Page 49: Scala Types of Types @ Lambda Days

Type Alias trait Builder { type From; type To; def make(in: From): To }!

trait StringBuilder extends Builder {! type To = String!}

trait FromBytesBuilder extends Builder {! type From = Array[Byte]!}

object `bytes -> string` extends Builder! with FromBytesBuilder! with StringBuilder {! ! def make(in: From): To = new String(in)! }!

Page 50: Scala Types of Types @ Lambda Days

Type Alias trait Builder { type From; type To; def make(in: From): To }!

object `bytes -> string` extends Builder {! type From = Array[Bytes]! type To = String!! def make(in: From): To = new String(in)! }!

Page 51: Scala Types of Types @ Lambda Days

Phantom Types

Page 52: Scala Types of Types @ Lambda Days

Phantom Types

uhm… where are they?

Exactly!

Phantom Types are never actually instanciated.

Page 53: Scala Types of Types @ Lambda Days

Phantom Types

sealed trait DoorState!final class Open extends DoorState!final class Closed extends DoorState!

Marker traits:

Page 54: Scala Types of Types @ Lambda Days

Phantom Types

sealed trait DoorState!final class Open extends DoorState!final class Closed extends DoorState!

Marker traits:

trait Door[State <: DoorState] {!! def open[T >: State <: Closed](): Door[Open] !!! def close[T >: State <: Open](): Door[Closed]!!}!!

Page 55: Scala Types of Types @ Lambda Days

Phantom Types

Only slide in this talk with implementation!

class Door[State <: DoorState] private () {!! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]!! def close[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]!}!!object Door { def apply() = new Door[Closed] }

Page 56: Scala Types of Types @ Lambda Days

Phantom Types

sealed trait DoorState!final class Open extends DoorState!final class Closed extends DoorState!

Marker traits:

class Door[State <: DoorState] private () {!! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]!! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]!}!!object Door { def apply() = new Door[Closed] }

Page 57: Scala Types of Types @ Lambda Days

Phantom Types

sealed trait DoorState!final class Open extends DoorState!final class Closed extends DoorState!

Marker traits:

class Door[State <: DoorState] private () {!! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]!! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]!}!!object Door { def apply() = new Door[Closed] }

Page 58: Scala Types of Types @ Lambda Days

Phantom Types

sealed trait DoorState!final class Open extends DoorState!final class Closed extends DoorState!

Marker traits:

class Door[State <: DoorState] private () {!! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]!! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]!}!!object Door { def apply() = new Door[Closed] }

Page 59: Scala Types of Types @ Lambda Days

Phantom Types

sealed trait DoorState!final class Open extends DoorState!final class Closed extends DoorState!

Marker traits:

class Door[State <: DoorState] private () {!! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]!! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]!}!!object Door { def apply() = new Door[Closed] }

Page 60: Scala Types of Types @ Lambda Days

Phantom Types

val closed = Door()!// closed: Door[Closed]

Page 61: Scala Types of Types @ Lambda Days

Phantom Types

val closed = Door()!// closed: Door[Closed]!!val opened = closed.open()!// opened: Door[Open]

Page 62: Scala Types of Types @ Lambda Days

Phantom Types

val closed = Door()!// closed: Door[Closed]!!val opened = closed.open()!// opened: Door[Open]!!val closedAgain = opened.close()!// closedAgain: Door[Closed]!

Page 63: Scala Types of Types @ Lambda Days

Phantom Types

val closed = Door()!// closed: Door[Closed]!!val opened = closed.open()!// opened: Door[Open]!!val closedAgain = opened.close()!// closedAgain: Door[Closed]!!closed.close()!error: type arguments [Closed] do not conform to method close's type parameter bounds [T >: Closed <: Open]

Page 64: Scala Types of Types @ Lambda Days

Phantom Types

val closed = Door()!// closed: Door[Closed]!!val opened = closed.open()!// opened: Door[Open]!!val closedAgain = opened.close()!// closedAgain: Door[Closed]!!closed.close()!error: type arguments [Closed] do not conform to method close's type parameter bounds [T >: Closed <: Open]!!opened.open()!error: type arguments [Open] do not conform to method !open's type parameter bounds [T >: Open <: Closed]

Page 65: Scala Types of Types @ Lambda Days

Higher Kinded Types

Page 66: Scala Types of Types @ Lambda Days

Kind: x

Int!

scala> :kind -v 42!!scala.Int's kind is A!*!!This is a proper type.

Proper Kind

Page 67: Scala Types of Types @ Lambda Days

Kind: x -> x

List[+A]!

scala> :kind -v List!!scala.collection.immutable.List's kind is F[+A]!* -(+)-> *!!This is a type constructor: !a 1st-order-kinded type.

Type Constructor

Page 68: Scala Types of Types @ Lambda Days

Kind: (x -> x) -> x

import language.higherKinds! !class Functor[M[_]]!

scala> :kind -v Functor[List]!!Functor's kind is X[F[A]]!(* -> *) -> *!!This is a type constructor that takes type constructor(s): !a higher-kinded type

Higher Kind

Page 69: Scala Types of Types @ Lambda Days

Higher Kinded Types

import scala.language.higherKinds!!trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]!}

takes Type Constructor

Page 70: Scala Types of Types @ Lambda Days

Higher Kinded Typesimport scala.language.higherKinds!!trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]!}

trait Functor [List] {! def map[Int,String] (fn: Int => String)! (fa: List[Int]): List[String]!}

Page 71: Scala Types of Types @ Lambda Days

Higher Kinded Typesimport scala.language.higherKinds!!trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]!}

val funct = new Functor[List] {! def map[String, Int] ! (f: String => Int)! (fa: List[String])! : List[Int] = fa map f // cheating ;-)!}

Page 72: Scala Types of Types @ Lambda Days

Higher Kinded Typesimport scala.language.higherKinds!!trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]!}

val funct = new Functor[List] {! def map[String, Int] ! (f: String => Int)! (fa: List[String]): List[Int] = !! ! ! ! ! fa map f // cheating ;-)! }

val f: Int => String = _.toString!funct.map(f)(List(1, 2)) == List("1", "2")!

Page 73: Scala Types of Types @ Lambda Days

Power up: Ad-Hoc Polymorphismtrait Container[M[_]] { ! def put[A](x: A): M[A]; def get[A](m: M[A]): A !}!

implicit val listContainer = new Container[List] { ! def put[A](x: A) = List(x)! def get[A](m: List[A]) = m.head !}!!implicit val optionContainer = new Container[Some] {! def put[A](x: A) = Some(x);! def get[A](m: Some[A]) = m.get !}!

Page 74: Scala Types of Types @ Lambda Days

Power up: Ad-Hoc Polymorphismtrait Container[M[_]] { ! def put[A](x: A): M[A]; def get[A](m: M[A]): A !}!

def tupleize[M[_]: Container, A, B]! (fst: M[A], snd: M[B]) ! (implicit c: Container[M]): M[(A, B)] = ! c.put(c.get(fst), c.get(snd))

tupleize(Some(1), Some(2))!Some((1,2)): Some[(Int, Int)]!!tupleize(List(1), List(“2”))!List((1,2)): List[(Int, String)]!

Page 75: Scala Types of Types @ Lambda Days

Power up: Ad-Hoc Polymorphismtrait Container[M[_]] { ! def put[A](x: A): M[A]; def get[A](m: M[A]): A !}!

def tupleize[M[_]: Container, A, B]! (fst: M[A], snd: M[B]) ! (implicit c: Container[M]): M[(A, B)] = ! c.put(c.get(fst), c.get(snd))

tupleize(Some(1), Some(2))!Some((1,2)): Some[(Int, Int)]!!tupleize(List(1), List(“2”))!List((1,2)): List[(Int, String)]!

Page 76: Scala Types of Types @ Lambda Days

Type Class

Page 77: Scala Types of Types @ Lambda Days

Type Class A.K.A. “ad-hoc polymorphism”

Page 78: Scala Types of Types @ Lambda Days

Type Class A.K.A. “More pattern, than type”

Page 79: Scala Types of Types @ Lambda Days

Type Class A.K.A. “Stay in this room”

Page 80: Scala Types of Types @ Lambda Days

Type Class A.K.A. “Stay in this room”

Jerzy has an entire talk about them

Page 81: Scala Types of Types @ Lambda Days

Type Class

// no type classes yet!trait Writeable[Out] {! def write: Out!}!!case class Num(a: Int, b: Int) extends Writeable[Json] {! def write = Json.toJson(this)!}!

Page 82: Scala Types of Types @ Lambda Days

Type Classtrait Writes[In, Out] { ! def write(in: In): Out!}!!!trait Writeable[Self] { ! def writeAs[Out]()! (implicit writes: Writes[Self, Out]): Out =!! ! ! ! writes write this! }!!!!!!

implicit val jsonNum = Writes[Num, Json] {! def write(n: Num) = Json.toJson(n)!}!!case class Num(a: Int) extends Writeable[Num]

Separated “what” from “who”Separated “what” from “who”

Page 83: Scala Types of Types @ Lambda Days

Type Classtrait Writes[In, Out] { ! def write(in: In): Out!}!!!trait Writeable[Self] { ! def writeAs[Out]()! (implicit writes: Writes[Self, Out]): Out =!! ! ! ! writes write this! }!!!!!!

implicit val jsonNum = Writes[Num, Json] {! def write(n: Num) = Json.toJson(n)!}!!case class Num(a: Int) extends Writeable[Num]

Implicit parameter

Implicit value

Page 84: Scala Types of Types @ Lambda Days

Type Class

implicit val jsonNum = Writes[Num, Json] { ! def (n1: Num, n2: Num) = n1.a < n1.!}!!case class Num(a: Int) extends Writeable[Num]

Page 85: Scala Types of Types @ Lambda Days

Type Class

implicit val jsonNum = Writes[Num, Json] { ! def (n1: Num, n2: Num) = n1.a < n1.!}!!case class Num(a: Int) extends Writeable[Num]

you write:

val jsonNum = Num(12).writeAs[Json]()!

Page 86: Scala Types of Types @ Lambda Days

Type Class

implicit val jsonNum = Writes[Num, Json] { ! def (n1: Num, n2: Num) = n1.a < n1.!}!!case class Num(a: Int) extends Writeable[Num]

you write:

val jsonNum = Num(12).writeAs[Json]()!

val jsonNum = Num(12).writeAs[Json]()(jsonNum)!

compiler does:

Page 87: Scala Types of Types @ Lambda Days

Links & Kudos

Page 88: Scala Types of Types @ Lambda Days

ktoso/scala-types-of-types @ github

12444 words and growing

Page 89: Scala Types of Types @ Lambda Days

Other Types of Types

type annotation unified type system

bottom types type variance

traits type refinements

type alias abstract type member

case class value class type class

universal trait self type annotation

phantom type structural type

path dependent type

type projection self recursive type type constructor specialized type dynamic type

existential type type lambda

algebraic data type

Page 90: Scala Types of Types @ Lambda Days

Links and Kudoshttp://docs.scala-lang.org/

!http://ktoso.github.io/scala-types-of-types/

!!

http://blog.echo.sh/post/68636331334/experimenting-with-peano-numbers-on-scalas-type-system-1 !

http://stackoverflow.com/questions/6246719/what-is-a-higher-kinded-type-in-scala !

http://twitter.github.io/scala_school/advanced-types.html !

https://github.com/earldouglas/scala-scratchpad/tree/master/type-lambdas !

http://www.scala-lang.org/old/node/136 !

http://eed3si9n.com/learning-scalaz/polymorphism.html !!!

Page 91: Scala Types of Types @ Lambda Days

K.Malawski @ ebay.com Konrad.Malwski @ geecon.org t: ktosopl / g: ktoso blog: project13.pl Lambda Days 2014 @ Kraków

Dziękuję! Thank you! あろがとう!

!

(guess “type” occurrences)