scala types of types @ lambda days

Post on 10-May-2015

2.127 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

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

Scala’s Types of Types

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

_ @

Konrad `@ktosopl` Malawski

geecon.org Java.pl / KrakowScala.pl

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

meetup.com/Lambda-Lounge-Krakow

Types

Types“Implementation is an implementation detail.” ~ ktoso

Types in Scala

Types in Scala

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! ^

Types in Scala

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

Types are: !

static strong error: type mismatch;!

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

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"

Types in Scala

Types are: !

static strong

inferred annotated after :

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

! val n: Int = 2

Types with Traits

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:

Types with Traits

Traits are: !

interfaces with implementation

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

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?!

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

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

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

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

Type Refinement

Type Refinement

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

trait Human!trait Robot

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

Compound Types

Compound Types

are intersections

of types !

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

Compound Types

are intersections

!

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

open() close()

Compound Types

are intersections

!

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

Compound Types

are intersections

!

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

Compound Types

this.type

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

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

!

Type Parameters

!

Type Parameters [Type Variance]

!

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

Type Parameters

class C[T]

type parameter

type constructor

Type Variance

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

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

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)!

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]!!!

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]!!!

Structural Type

Structural Types

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

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

Structural TypesKinda’ like “duck typing”

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

structural type

Structural Types

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

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

type alias

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)

Type Member

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

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!!}

Type Alias

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!

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!

Type Alias

From Type Parameter to Type Members

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

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)! }!

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)! }!

Phantom Types

Phantom Types

uhm… where are they?

Exactly!

Phantom Types are never actually instanciated.

Phantom Types

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

Marker traits:

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]!!}!!

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] }

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] }

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] }

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] }

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] }

Phantom Types

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

Phantom Types

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

Phantom Types

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

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]

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]

Higher Kinded Types

Kind: x

Int!

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

Proper Kind

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

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

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

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]!}

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 ;-)!}

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")!

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 !}!

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)]!

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)]!

Type Class

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

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

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

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

Jerzy has an entire talk about them

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)!}!

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”

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

Type Class

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

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]()!

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:

Links & Kudos

ktoso/scala-types-of-types @ github

12444 words and growing

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

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 !!!

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)

top related