SlideShare une entreprise Scribd logo
1  sur  35
Télécharger pour lire hors ligne
практичные типы
 Software Craftsmanship BY, @remeniuk




   λ
в теории

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

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

                              одни достоинства
в мейнстриме



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
Бенжамин Пирс приукрашал картину?

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

*          Int, Boolean, String
           конкретные типы
* -> *     List[T], Map[K, V]
           функции на типах / полиморфные
           типы / конструкторы типов
(* -> *) -> *
trait Functor[F[_]] {
  def map[A, B](r: F[A], f: A => B): F[B]
}

map - функция высшего порядка; в качестве
переметра приниимает функции
Functor - тип высшего порядка; в качестве
параметров принимает конструкторы типов
λ-куб
      Fω<:
               Fω        CC
F<:
         F


               λω
λ<:
         λ->        LF
Fω<:
вариантность типов и System F<:



  F<:
        F




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



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

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

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


List<? extends List<? extends Number>> l =
                new ArrayList<List<Number>>();
вариантность типов в 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]
trait Suit
trait 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"))
trait Suit
trait 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"))
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
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
неявная конверсия типов

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


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


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




                   [[A -> B]]
неявная конверсия типов

trait Card

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

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


 import Hand._
 List[Card]().weight
                                      неявный
                                      контекст
тип List[Card] "видимый как" Hand
ограничения на "вид"

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]())
ограничения на контекст
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)
ограничения на контекст
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)
ограничения на контекст
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)
ограничения на контекст
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
реификация vs стирание типов

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

Scala имитирует реификацию, и поддерживает
типы высших порядков
имитация реификации
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
зависимые
 типы




λ->          LF
зависимые типы
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")) // не компилируется
черная магия

     типы-фантомы
     тип-объеднение и гетерогенные
списки
class Dealer[T <: Stage : Manifest](deck: List[Card]) {
  def deal(cards: Int, recipient: Actor): Dealer = /*...*/
}


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

sealed trait Stage
trait Preflop extends Stage
trait Flop extends Stage
trait Turn extends Stage
trait River extends Stage
trait 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] {}
типы-фантомы

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)
trait HandEvaluator {
   def compare(hand1: List[Card], hand2: List[Card]): Int
}



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

class Card

object Card {
   type NoCards = HNil
   type HandCards = Card :: Card :: NoCards
   type FlopCards = Card :: Card :: Card :: NoCards
   type TurnCards = Card :: FlopCards
    type RiverCards = Card :: TurnCards
}
гетерогенный список и тип-объединение

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

val handCards = new Card :: new Card :: HNil
val 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)
[Не]практичные типы

Contenu connexe

Plus de Vasil Remeniuk

Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14Vasil Remeniuk
 
Cake pattern. Presentation by Alex Famin at scalaby#14
Cake pattern. Presentation by Alex Famin at scalaby#14Cake pattern. Presentation by Alex Famin at scalaby#14
Cake pattern. Presentation by Alex Famin at scalaby#14Vasil Remeniuk
 
Scala laboratory: Globus. iteration #3
Scala laboratory: Globus. iteration #3Scala laboratory: Globus. iteration #3
Scala laboratory: Globus. iteration #3Vasil Remeniuk
 
Testing in Scala by Adform research
Testing in Scala by Adform researchTesting in Scala by Adform research
Testing in Scala by Adform researchVasil Remeniuk
 
Spark Intro by Adform Research
Spark Intro by Adform ResearchSpark Intro by Adform Research
Spark Intro by Adform ResearchVasil Remeniuk
 
Types by Adform Research, Saulius Valatka
Types by Adform Research, Saulius ValatkaTypes by Adform Research, Saulius Valatka
Types by Adform Research, Saulius ValatkaVasil Remeniuk
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform ResearchVasil Remeniuk
 
Scalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex GryzlovScalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex GryzlovVasil Remeniuk
 
Scalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex GryzlovScalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex GryzlovVasil Remeniuk
 
Spark by Adform Research, Paulius
Spark by Adform Research, PauliusSpark by Adform Research, Paulius
Spark by Adform Research, PauliusVasil Remeniuk
 
Scala Style by Adform Research (Saulius Valatka)
Scala Style by Adform Research (Saulius Valatka)Scala Style by Adform Research (Saulius Valatka)
Scala Style by Adform Research (Saulius Valatka)Vasil Remeniuk
 
Spark intro by Adform Research
Spark intro by Adform ResearchSpark intro by Adform Research
Spark intro by Adform ResearchVasil Remeniuk
 
SBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaSBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaVasil Remeniuk
 
Scala laboratory: Globus. iteration #2
Scala laboratory: Globus. iteration #2Scala laboratory: Globus. iteration #2
Scala laboratory: Globus. iteration #2Vasil Remeniuk
 
Testing in Scala. Adform Research
Testing in Scala. Adform ResearchTesting in Scala. Adform Research
Testing in Scala. Adform ResearchVasil Remeniuk
 
Scala laboratory. Globus. iteration #1
Scala laboratory. Globus. iteration #1Scala laboratory. Globus. iteration #1
Scala laboratory. Globus. iteration #1Vasil Remeniuk
 
Cassandra + Spark + Elk
Cassandra + Spark + ElkCassandra + Spark + Elk
Cassandra + Spark + ElkVasil Remeniuk
 
Опыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событияхОпыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событияхVasil Remeniuk
 
Funtional Reactive Programming with Examples in Scala + GWT
Funtional Reactive Programming with Examples in Scala + GWTFuntional Reactive Programming with Examples in Scala + GWT
Funtional Reactive Programming with Examples in Scala + GWTVasil Remeniuk
 

Plus de Vasil Remeniuk (20)

Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14
 
Cake pattern. Presentation by Alex Famin at scalaby#14
Cake pattern. Presentation by Alex Famin at scalaby#14Cake pattern. Presentation by Alex Famin at scalaby#14
Cake pattern. Presentation by Alex Famin at scalaby#14
 
Scala laboratory: Globus. iteration #3
Scala laboratory: Globus. iteration #3Scala laboratory: Globus. iteration #3
Scala laboratory: Globus. iteration #3
 
Testing in Scala by Adform research
Testing in Scala by Adform researchTesting in Scala by Adform research
Testing in Scala by Adform research
 
Spark Intro by Adform Research
Spark Intro by Adform ResearchSpark Intro by Adform Research
Spark Intro by Adform Research
 
Types by Adform Research, Saulius Valatka
Types by Adform Research, Saulius ValatkaTypes by Adform Research, Saulius Valatka
Types by Adform Research, Saulius Valatka
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform Research
 
Scalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex GryzlovScalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex Gryzlov
 
Scalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex GryzlovScalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex Gryzlov
 
Spark by Adform Research, Paulius
Spark by Adform Research, PauliusSpark by Adform Research, Paulius
Spark by Adform Research, Paulius
 
Scala Style by Adform Research (Saulius Valatka)
Scala Style by Adform Research (Saulius Valatka)Scala Style by Adform Research (Saulius Valatka)
Scala Style by Adform Research (Saulius Valatka)
 
Spark intro by Adform Research
Spark intro by Adform ResearchSpark intro by Adform Research
Spark intro by Adform Research
 
SBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaSBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius Valatka
 
Scala laboratory: Globus. iteration #2
Scala laboratory: Globus. iteration #2Scala laboratory: Globus. iteration #2
Scala laboratory: Globus. iteration #2
 
Testing in Scala. Adform Research
Testing in Scala. Adform ResearchTesting in Scala. Adform Research
Testing in Scala. Adform Research
 
Scala laboratory. Globus. iteration #1
Scala laboratory. Globus. iteration #1Scala laboratory. Globus. iteration #1
Scala laboratory. Globus. iteration #1
 
Cassandra + Spark + Elk
Cassandra + Spark + ElkCassandra + Spark + Elk
Cassandra + Spark + Elk
 
Опыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событияхОпыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событиях
 
ETL со Spark
ETL со SparkETL со Spark
ETL со Spark
 
Funtional Reactive Programming with Examples in Scala + GWT
Funtional Reactive Programming with Examples in Scala + GWTFuntional Reactive Programming with Examples in Scala + GWT
Funtional Reactive Programming with Examples in Scala + GWT
 

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

  • 1. практичные типы Software Craftsmanship BY, @remeniuk λ
  • 2. в теории система типов - статическая аппроксимация программы во время выполнения Бенжамин Пирс, "TAPL" что дают типы? производительность безопасность документорованность оптимизации компилятора лучшие абстракции одни достоинства
  • 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
  • 4. Бенжамин Пирс приукрашал картину? нет. просто он говорил не о Java (C#, C++, ..)
  • 5. 1, true, "abc" - термы / конкретные значения / абстракции нулевого порядка x => x + 1 - функция / абстракции первого порядка (полиморфны, т.к. конструируют множественные конкретные значения) * Int, Boolean, String конкретные типы * -> * List[T], Map[K, V] функции на типах / полиморфные типы / конструкторы типов
  • 6. (* -> *) -> * trait Functor[F[_]] { def map[A, B](r: F[A], f: A => B): F[B] } map - функция высшего порядка; в качестве переметра приниимает функции Functor - тип высшего порядка; в качестве параметров принимает конструкторы типов
  • 7. λ-куб Fω<: Fω CC F<: F λω λ<: λ-> LF
  • 9. вариантность типов и System F<: F<: F λ<: λ->
  • 10. вариантность типов и System F<: S подтип T, конструктор типов C<U> => C<S> подтип/супертип/? C<T>
  • 11. вариантность типов в Java cписки ковариантны: S[] подтип T[] oстальные типы - инварианты workaround: имитация вариантности в месте вызова с помощью органиченных экзистенциальных типов List<? extends List<? extends Number>> l = new ArrayList<List<Number>>();
  • 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]
  • 13. trait Suit trait 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"))
  • 14. trait Suit trait 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"))
  • 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
  • 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
  • 17. неявная конверсия типов 1. class A { def foo(): Unit } 2. class B ...магия... 3. val b = new B() b.foo() // b был неявно конвертирован в A [[A -> B]]
  • 18. неявная конверсия типов trait Card class Hand(cards: List[Card]) { def weight = /*..*/ } object Hand { implicit def toHand(cards: List[Card]) = new Hand(cards) } import Hand._ List[Card]().weight неявный контекст тип List[Card] "видимый как" Hand
  • 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]())
  • 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)
  • 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)
  • 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)
  • 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
  • 24. реификация vs стирание типов C#, F# (CLR) реализует реификацию типов, но не поддерживает типы высших порядков Java (JVM) стирает типы, и не поддерживает типы высших порядков Scala имитирует реификацию, и поддерживает типы высших порядков
  • 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
  • 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")) // не компилируется
  • 28. черная магия типы-фантомы тип-объеднение и гетерогенные списки
  • 29. class Dealer[T <: Stage : Manifest](deck: List[Card]) { def deal(cards: Int, recipient: Actor): Dealer = /*...*/ } если бы мы могли гарантировать на уровне типов, что дилер выдаст всем нужное количество кард...
  • 30. типы-фантомы sealed trait Stage trait Preflop extends Stage trait Flop extends Stage trait Turn extends Stage trait River extends Stage trait 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] {}
  • 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)
  • 32. trait HandEvaluator { def compare(hand1: List[Card], hand2: List[Card]): Int } если бы мы могли проверять не только тип списка, но и его содержимое...
  • 33. гетерогенный список class Card object Card { type NoCards = HNil type HandCards = Card :: Card :: NoCards type FlopCards = Card :: Card :: Card :: NoCards type TurnCards = Card :: FlopCards type RiverCards = Card :: TurnCards }
  • 34. гетерогенный список и тип-объединение trait HandEvaluator { def compare[T: (HandCards ∨ (RiverCards :: HandCards))#λ] (hand1: T, hand2: T): Int } val handCards = new Card :: new Card :: HNil val 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)