[Не]практичные типы

35
практичные типы Software Craftsmanship BY, @remeniuk λ

Upload: vasil-remeniuk

Post on 26-May-2015

1.256 views

Category:

Documents


1 download

DESCRIPTION

Презентация, которая была сделана на 11-ой встрече коммьюнити Software Craftsmanship BY

TRANSCRIPT

Page 1: [Не]практичные типы

практичные типы Software Craftsmanship BY, @remeniuk

λ

Page 2: [Не]практичные типы

система типов - статическая аппроксимация программы во время выполнения Бенжамин Пирс, "TAPL"

что дают типы?

производительностьбезопасностьдокументорованностьоптимизации компиляторалучшие абстракции

одни достоинства

в теории

Page 3: [Не]практичные типы

public Map<Desk<Poker>, List<Player<Poker>> getPlayersPerDesks(){

Map<Desk<Poker>, List<Player<Poker>> players= new HashMap<Desk<Poker>, List<Player<Poker>>();

...return players;

}

boilerplate

в мейнстриме

Page 4: [Не]практичные типы

Бенжамин Пирс приукрашал картину?

нет. просто он говорил не о Java (C#, C++, ..)

Page 5: [Не]практичные типы

1, true, "abc" - термы / конкретные значения / абстракции нулевого порядкаx => x + 1 - функция / абстракции первого порядка (полиморфны, т.к. конструируют множественные конкретные значения)

* Int, Boolean, String конкретные типы

* -> * List[T], Map[K, V] функции на типах / полиморфные типы / конструкторы типов

Page 6: [Не]практичные типы

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

map - функция высшего порядка; в качестве переметра приниимает функцииFunctor - тип высшего порядка; в качестве параметров принимает конструкторы типов

(* -> *) -> *

Page 7: [Не]практичные типы

λ-куб

λ->

λω

F

Fω CC

LF

F<:

Fω<:

λ<:

Page 8: [Не]практичные типы

Fω<:

Page 9: [Не]практичные типы

вариантность типов и System F<:

λ->

FF<:

λ<:

Page 10: [Не]практичные типы

вариантность типов и System F<:

S подтип T, конструктор типов C<U> => C<S> подтип/супертип/? C<T>

Page 11: [Не]практичные типы

вариантность типов в Java

cписки ковариантны: S[] подтип T[] oстальные типы - инварианты

workaround: имитация вариантности в месте вызова с помощью органиченных экзистенциальных типов

List<? extends List<? extends Number>> l = new ArrayList<List<Number>>();

Page 12: [Не]практичные типы

вариантность типов в Scala

C[+U] - ковариантность, S подтип T => C[S] подтип C[T]

C[-U] - контрвариантность, S подтип T => C[T] супертип C[S]

С[U] - инвариантность (как в Java), S подтип T => C[T] ? C[S]

Page 13: [Не]практичные типы

trait Suittrait Spades extends Suit

class Card[T <: Suit](rank: String)

class Hand[A <: Suit](cards: List[Card[A]] = Nil) { def add[B >: A <: Suit](card: Card[B]): Hand[B] = new Hand[B](card :: cards)}

val hand1: Hand[Spades] = new Hand.add(new Card[Spades]("A")).add(new Card[Spades]("Q"))val hand2: Hand[Suit] = new Hand.add(new Card[Spades]("A")).add(new Card[Hearts]("Q"))

Page 14: [Не]практичные типы

trait Suittrait Spades extends Suit

class Card[+T <: Suit](rank: String)

class Hand[A <: Suit](cards: List[Card[A]] = Nil) { def add[B >: A <: Suit](card: Card[B]): Hand[B] = new Hand[B](card :: cards)}

val hand1: Hand[Spades] = new Hand.add(new Card[Spades]("A")).add(new Card[Spades]("Q"))val hand2: Hand[Suit] = new Hand.add(new Card[Spades]("A")).add(new Card[Hearts]("Q"))

Page 15: [Не]практичные типы

class HandEvaluator[T <: Suit] (val evaluate: List[Card[T]] => Int)

val flushEval = new HandEvaluator( (_: List[Card[Spades]]) => 1000)val genEval = new HandEvaluator( (_: List[Card[Suit]]) => 100)

val hand1: Hand[Spades] = ...

> println(hand1.evaluate(flushEval))1000> println(hand1.evaluate(genEval))

Suit >:Spades, but class HandEvaluator is invariant in type T

Page 16: [Не]практичные типы

class HandEvaluator[-T <: Suit] (val evaluate: List[Card[T]] => Int)

val flushEval = new HandEvaluator( (_: List[Card[Spades]]) => 1000)val genEval = new HandEvaluator( (_: List[Card[Suit]]) => 100)

val hand1: Hand[Spades] = ...

> println(hand1.evaluate(flushEval))1000> println(hand1.evaluate(genEval))100

Page 17: [Не]практичные типы

неявная конверсия типов

1. class A { def foo(): Unit }2. class B

...магия... 3. val b = new B()

b.foo() // b был неявно конвертирован в A

[[A -> B]]

Page 18: [Не]практичные типы

неявная конверсия типов

trait Card

class Hand(cards: List[Card]) { def weight = /*..*/ }

object Hand { implicit def toHand(cards: List[Card]) = new Hand(cards)}

тип List[Card] "видимый как" Hand

неявный контекст

import Hand._List[Card]().weight

Page 19: [Не]практичные типы

ограничения на "вид"

class HandComparator {

def compare[T <% Hand](hand1: T, hand2: T) = hand1.weight compareTo hand2.weight

}

new HandComparator().compare(new Hand(Nil), new Hand(Nil))new HandComparator().compare(List[Card](), List[Card]())

Page 20: [Не]практичные типы

ограничения на контекст

class Hand[A <: Suit](cards: List[Card[A]] = Nil) {

def add[B >: A <: Suit](card: Card[B]): Hand[B] = new Hand[B](card :: cards)

def evaluate(evaluator: HandEvaluator[A]) = evaluator.evaluate(cards)

}

val flushEval = new HandEvaluator( (_: List[Card[Spades]]) => 1000)val genEval = new HandEvaluator( (_: List[Card[Suit]]) => 100)

Page 21: [Не]практичные типы

ограничения на контекст

class Hand[A <: Suit](cards: List[Card[A]] = Nil) {

def add[B >: A <: Suit](card: Card[B]): Hand[B] = new Hand[B](card :: cards)

def evaluate(evaluator: HandEvaluator[A]) =evaluator.evaluate(cards)

}

implicit val flushEval = new HandEvaluator( (_: List[Card[Spades]]) => 1000)implicit val genEval = new HandEvaluator( (_: List[Card[Suit]]) => 100)

помещаем в неявный контекст

Page 22: [Не]практичные типы

ограничения на контекст

class Hand[A <: Suit : HandEvaluator](cards: List[Card[A]] = Nil) {

def add[B >: A <: Suit](card: Card[B]): Hand[B] = new Hand[B](card :: cards)

def evaluate = implicitly[HandEvaluator[A]].evaluate(cards)

}

implicit val flushEval = new HandEvaluator( (_: List[Card[Spades]]) => 1000)implicit val genEval = new HandEvaluator( (_: List[Card[Suit]]) => 100)

Page 23: [Не]практичные типы

ограничения на контекст

val h1 = Hand().add(Card[Hearts]("A")).add(Card[Hearts]("Q"))val h2 = Hand().add(Card[Spades]("A")).add(Card[Spades]("Q"))val h3 = Hand().add(Card[Spades]("A")).add(Card[Hearts]("Q"))

> println(h1.evaluate) could not find implicit value for evidence parameter of type by.scala.pokertypes.variance.HandEvaluator[B]> println(h2.evaluate) 1000> println(h3.evaluate)100

Page 24: [Не]практичные типы

реификация vs стирание типов

C#, F# (CLR) реализует реификацию типов, но не поддерживает типы высших порядковJava (JVM) стирает типы, и не поддерживает типы высших порядков

Scala имитирует реификацию, и поддерживает типы высших порядков

Page 25: [Не]практичные типы

имитация реификации

def evaluate[T <: Suit : Manifest](hand: Hand[T]) = { print("Type parameter class: " + manifest[T].erasure) if (manifest[T] <:< manifest[Spades]) print("; Spades")

else print("; Random")}

val h2 = Hand().add(Card[Spades]("A")).add(Card[Spades]("Q"))

> println(evaluate(hand1))Type parameter class: interface Spades; Spades> println(evaluate(hand2))Type parameter class: interface Suit; Random

Page 26: [Не]практичные типы

зависимые типы

LFλ->

Page 27: [Не]практичные типы

зависимые типы

case class Desk(id: Int) {

case class Action(name: String)

def log(action: Action) = /*..*/}

desk1.log(desk1.Action("Small Blind"))

desk1.log(desk2.Action("Small Blind")) // не компилируется

Page 28: [Не]практичные типы

черная магия

типы-фантомы тип-объеднение и гетерогенные

списки

Page 29: [Не]практичные типы

class Dealer[T <: Stage : Manifest](deck: List[Card]) { def deal(cards: Int, recipient: Actor): Dealer = /*...*/}

если бы мы могли гарантировать на уровне типов, что дилер выдаст всем нужное количество кард...

Page 30: [Не]практичные типы

типы-фантомы

sealed trait Stagetrait Preflop extends Stagetrait Flop extends Stagetrait Turn extends Stagetrait River extends Stagetrait Showdown extends Stage

trait StageOrder[Last <: Stage, Current <: Stage]

implicit val gotoFlop = new StageOrder[Preflop, Flop] {}implicit val gotoTurn = new StageOrder[Flop, Turn] {}implicit val gotoRiver = new StageOrder[Turn, River] {}

Page 31: [Не]практичные типы

типы-фантомы

class Dealer[LastStage <: Stage](deck: List[Card]) {

type IsCurrentStageValid[T <: Stage] = StageOrder[LastStage, T]

def deal[CurrentStage <: Stage : IsCurrentStageValid](recipient: Actor): Dealer[CurrentStage] = {/*...*/}

}

dealer.deal[Flop](desk).deal[Turn](desk).deal[River](desk)dealer.deal[Flop](desk).deal[Flop](desk).deal[River](desk)

Page 32: [Не]практичные типы

trait HandEvaluator {def compare(hand1: List[Card], hand2: List[Card]): Int

}

если бы мы могли проверять не только тип списка, но и его содержимое...

Page 33: [Не]практичные типы

гетерогенный список

class Card

object Card {type NoCards = HNiltype HandCards = Card :: Card :: NoCardstype FlopCards = Card :: Card :: Card :: NoCardstype TurnCards = Card :: FlopCards

type RiverCards = Card :: TurnCards}

Page 34: [Не]практичные типы

гетерогенный список и тип-объединение

trait HandEvaluator {

def compare[T: (HandCards ∨ (RiverCards :: HandCards))#λ] (hand1: T, hand2: T): Int

}

val handCards = new Card :: new Card :: HNilval communityCards = new Card :: new Card :: new Card :: new Card :: new Card :: HNil

handEvaluator.compare(handCards, handCards)handEvaluator.compare(communityCards :: handCards, communityCards :: handCards)handEvaluator.compare(handCards, communityCards)

Page 35: [Не]практичные типы