Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Polimorfismo cosa – Milano Scala Group – September 2015

Polimorfismo cosa – Milano Scala Group – September 2015

Uno sguardo a 3 comuni strutture dati presenti nelle librerie standard di Scala ponendo l'attenzione sul polimorfismo parametrico offerto da alcune operazioni ed
il loro utilizzo con implementazioni sia in stile imperativo/procedurale sia funzionale.

A seguire un esempio pratico di utilizzo del polimorfismo ad-hoc per operazioni con strutture dati di type composti ed uno sguardo su come trarre benefici nell'utilizzare
in questi casi librerie come Scalaz.

Filippo Vitale

September 15, 2015
Tweet

More Decks by Filippo Vitale

Other Decks in Programming

Transcript

  1. package scala.collection Seq Set package scala.collection.immutable Map List HashSet HashMap

    package scala.collection.mutable ArrayBuffer HashSet HashMap http://docs.scala-lang.org/tutorials/FAQ/collections.html
  2. “When you get used to immutable data, ya kinda forget

    how to use mutable data in a sensible way.” – Jessica Kerr
  3. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString
  4. isEmpty size hasDefiniteSize ++ map flatMap filter remove partition groupBy

    foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString Metodi offerti da Traversable def map[B](f: A => B)
  5. isEmpty size hasDefiniteSize ++ map flatMap filter remove partition groupBy

    foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString Metodi offerti da Traversable def foreach(f: (A) => Unit): Unit def map[B](f: A => B)
  6. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString
  7. isEmpty size hasDefiniteSize ++ map flatMap filter remove partition groupBy

    foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString Metodi offerti da Traversable def foldLeft[B](z: B)(f: (B, A) => B): B
  8. isEmpty size hasDefiniteSize ++ map flatMap filter remove partition groupBy

    foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString Metodi offerti da Traversable def foldLeft[B](z: B)(f: (B, A) => B): B def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
  9. isEmpty size hasDefiniteSize ++ map flatMap filter remove partition groupBy

    foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString Metodi offerti da Traversable def foldLeft[B](z: B)(f: (B, A) => B): B def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
  10. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString
  11. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString def ++[B](that: Traversable[B]): Traversable[B]
  12. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString def ++[B](that: Traversable[B]): Traversable[B] Traversable Seq List
  13. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString def ++[B](that: Traversable[B]): Traversable[B] Traversable Set HashSet
  14. Set(1, 2, 3) ++ Set(4, 5, 6) == Set(5, 1,

    6, 2, 3, 4) Set(1, 2) ++ Set(2, 3) == Set(1, 2, 3)
  15. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString def ++[B](that: Traversable[B]): Traversable[B] Traversable Map HashMap
  16. Map[String, Set[Int]] “a” Set(1, 2) “key b” Set(4, 7, 5)

    “key c” Set(9, 4) “a” Set(2, 3) “key c” Set(3, 4) “key d” Set(5, 6)
  17. Map("a" -> Set(1, 2)) ++ Map("a" -> Set(2, 3)) ==

    ??? 1: Map("a" -> Set(1, 2)) 2: Map("a" -> Set(1, 2, 3)) 3: Map("a" -> Set(2, 3)) 4: RuntimeException 5: Compiler Error
  18. Map("a" -> Set(1, 2)) ++ Map("a" -> Set(2, 3)) ==

    ??? 1: 2: 3: Map("a" -> Set(2, 3)) 4: 5:
  19. Metodi offerti da Traversable isEmpty size hasDefiniteSize ++ map flatMap

    filter remove partition groupBy foreach reduceRightOpt head headOption tail last lastOption init take drop slice takeWhile forall exists count find foldLeft /: foldRight :\ reduceLeft reduceLeftOpt reduceRight dropWhile span splitAt toArray toList toIterable toSeq toStream sortWith mkString toString Seq Set Map ✔ ✔ ✘
  20. def blend(ma: Map[String, Set[Int]], mb: Map[String, Set[Int]]) : Map[String, Set[Int]]

    = { val result = mutable.Map() ++ ma mb foreach { case (k, v) => ??? } result.toMap }
  21. def blend(ma: Map[String, Set[Int]], mb: Map[String, Set[Int]]) : Map[String, Set[Int]]

    = { val result = mutable.Map() ++ ma mb foreach { case (k, v) => if (result.contains(k)) result += k -> (result(k) ++ v) else result += k -> v } result.toMap }
  22. def blend(ma: Map[String, Set[Int]], mb: Map[String, Set[Int]]) : Map[String, Set[Int]]

    = { } (ma /: mb) { case (result,(k, v)) => if (result.contains(k)) result + (k -> (result(k) ++ v)) else result + (k -> v) } val result = mutable.Map() ++ ma mb foreach { case (k, v) => if (result.contains(k)) result += k -> (result(k) ++ v) else result += k -> v } result.toMap
  23. def blend(ma: Map[String, Set[Int]], mb: Map[String, Set[Int]]) : Map[String, Set[Int]]

    = { (ma /: mb) { case (result,(k, v)) => if (result.contains(k)) result + (k -> (result(k) ++ v)) else result + (k -> v) } }
  24. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } }
  25. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } // .map(_ ++ v).getOrElse(v) }}
  26. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } // .map(_ ++ v).getOrElse(v) // .some(_ ++ v).none(v) }}
  27. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } // .map(_ ++ v).getOrElse(v) // .some(_ ++ v).none(v) // .fold(v)(_ ++ v) }}
  28. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } // .map(_ ++ v).getOrElse(v) // .some(_ ++ v).none(v) // .fold(v)(_ ++ v) // .cata(_ ++ v, v) }} “FP with Bananas, Lenses, Envelopes and Barbed Wire” – http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125 http://en.wikipedia.org/wiki/Catamorphism
  29. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } // .map(_ ++ v).getOrElse(v) // .some(_ ++ v).none(v) // .fold(v)(_ ++ v) // .cata(_ ++ v, v) }} http://stackoverflow.com/questions/5328007/why-doesnt-option-have-a-fold-method
  30. (ma /: mb) { case (result,(k, v)) => result +

    (k -> { result.get(k) match { case Some(vr) => vr ++ v case None => v } // .map(_ ++ v).getOrElse(v) // .some(_ ++ v).none(v) // .fold(v)(_ ++ v) // .cata(_ ++ v, v) }} http://stackoverflow.com/questions/5328007/why-doesnt-option-have-a-fold-method
  31. (ma /: mb) { case (result, (k, v)) => result

    + (k -> result.get(k).cata(_ ++ v, v)) } mb foreach { case (k, v) => result += (k -> result.get(k).cata(_ ++ v, v)) }
  32. (ma /: mb) { case (result, (k, v)) => result

    + (k -> result.get(k).cata(_ ++ v, v)) } mb foreach { case (k, v) => result += (k -> result.get(k).cata(_ ++ v, v)) }
  33. Map[String, Set[Int]] Map[String, Map[Int, Set[Int]]] def blend(ma: Map[String, Set[Int]], mb:

    Map[String, Set[Int]]) : Map[String, Set[Int]] = ??? def blend(ma: Map[String, Map[Int, Set[Int]]], mb: Map[String, Map[Int, Set[Int]]]) : Map[String, Map[Int, Set[Int]]] = ???
  34. Map[String, Set[Int]] Map[String, Map[Int, Set[Int]]] (ma /: mb) { case

    (result, (k, v)) => result + (k -> result.get(k).cata(_ ++ v, v)) } (ma /: mb) { case (result, (k, v)) => result + ??? // { ??? => { ??? } } }
  35. Map[String, Set[Int]] Map[String, Map[Int, Set[Int]]] trait Blendable[A] { def blend(ma:

    A, mb: A): A } new Blendable[...] { def blend(ma: ..., mb: ...): ... = ??? }
  36. Map[String, Set[Int]] Map[String, Map[Int, Set[Int]]] trait Blendable[A] { def blend(ma:

    A, mb: A): A } new Blendable[...] { def blend(ma: ..., mb: ...): ... = ??? } x10 Developer
  37. List utilizzando l’operatore binario ++ Set utilizzando l’operatore binario ++

    List(1, 2, 3) ++ List(4, 5, 6) == List(1, 2, 3, 4, 5, 6) Set(1, 2) ++ Set(2, 3) == Set(1, 2, 3)
  38. https://it.wikipedia.org/wiki/Propriet%C3%A0_di_chiusura Proprietà di chiusura ≝ ∀a, b ∈ T :

    a∙b ∈ T Per ogni a, b in T, il risultato dell’operazione a⋅b è in T: trait Semigroup[T] { def op(a: T, b: T): T } def op(a: Boolean, b: Boolean): Boolean def op(a: Int, b: Int): Boolean ✓ ✘
  39. https://it.wikipedia.org/wiki/Associativit%C3%A0 Legge Associativa ≝ ∀a, b, c ∈ T :

    (a∙b)∙c = a∙(b∙c) Ogni a, b e c in T soddisfano (a∙b)∙c = a∙(b∙c) trait Semigroup[T] { def op(a: T, b: T): T } ((a op b) op c) == (a op (b op c))
  40. import scalaz.syntax.semigroup._ import scalaz.std.list._ List(1, 2) |+| List(3, 4) res:

    List[Int] = List(1, 2, 3, 4) import scalaz.syntax.semigroup._ import scalaz.std.set._ Set(1, 2) |+| Set(2, 3) res: Set[Int] = Set(1, 2, 3)
  41. import scalaz.syntax.semigroup._ import scalaz.std.anyVal._ 1 |+| 2 |+| 3 res:

    Int = 6 import scalaz.syntax.semigroup._ import scalaz.std.string._ "a" |+| "b" |+| "c" res: String = "abc"
  42. /** * A semigroup in type F must satisfy two

    laws: * * - '''closure''': `∀ a, b in F, append(a, b)` is also in `F`. * - '''associativity''': `∀ a, b, c` in `F`, the equation * `append(append(a, b), c) = append(a, append(b , c))` holds. */ trait SemigroupLaw { def associative(f1: F, f2: F, f3: F)(implicit F: Equal[F]): Boolean = F.equal(append(f1, append(f2, f3)), append(append(f1, f2), f3)) }
  43. semigroup.laws[String].check semigroup.laws[Set[Int]].check semigroup.laws[List[String]].check semigroup.laws[Map[Int, Int]].check + semigroup.associative: OK, passed 100

    tests. + semigroup.associative: OK, passed 100 tests. + semigroup.associative: OK, passed 100 tests. + semigroup.associative: OK, passed 100 tests.
  44. Map("a" -> 1, "b" -> 4) |+| Map("a" -> 2)

    res: Map[…] = Map(a -> 3, b -> 4) “Some data structures form interesting semigroups as long as the types of the elements they contain also form semigroups.”
  45. Map("a" -> Set(1, 2)) |+| Map("a" -> Set(2, 3)) res:

    Map[…] = Map(a -> Set(1, 2, 3)) “adattato” da: Functional Programming in Scala - Part 3 - Chapter 10 Monoids ✓
  46. Map("a" -> Map("aa" -> Map("aaa" -> Map("aaaa" -> List(1, 3),

    "aaab" -> List(2, 4))))) |+| Map("a" -> Map("aa" -> Map("aaa" -> Map("aaaa" -> List(5, 7), "aaab" -> List(6, 8))))) Map(a->Map(aa->Map(aaa->Map(aaaa->List(1, 3, 5, 7), aaab->List(2, 4, 6, 8)))))
  47. “Experience indicates that nearly everybody has the wrong idea about

    the real bottlenecks in his programs” – Donald Knuth Computer programming as an art (1974) – http://dl.acm.org/citation.cfm?id=361612