Введение в Scalaz
- 3. Проекты, использующие Scalaz:
• https://github.com/argonaut-io/argonaut/
�� https://github.com/tpolecat/doobie
• https://github.com/oncue/remotely
• https://github.com/scalaz/scalaz-stream
• https://github.com/xuwei-k/httpz
• https://github.com/http4s/http4s
- 4. Функциональные структуры данных,
отсутствующие в Scala stdlib:
scalaz.NonEmptyList[A] Непустой список
scalaz.EphemeralStream[A] Правильный Stream
(аналог списков в Haskell)
scalaz.FingerTree[V, A] http://staff.city.ac.uk/~ross
/papers/FingerTree.html
scalaz.DList[A] Чистофункциональный
аналог ListBuffer
- 5. FingerTree[Int, A] Vector[A] TreeMap[Int, A] List[A]
head O(1) O(log32 n) O(log n) O(1)
tail O(1) O(log32 n) O(log n) O(1)
last O(1) O(log32 n) O(log n) O(n)
init O(1) O(log32 n) O(log n) O(n)
get(index) O(log n) O(log32 n) O(log n) O(n)
- 7. В ООП доминирует подтиповой
полиморфизм:
class Int {
def <(other: Int): Boolean = …
}
class Double {
def <(other: Double): Boolean = …
}
class String {
def <(other: String): Boolean = …
}
- 8. В ООП доминирует подтиповой
полиморфизм:
class Int {
def <(other: Int): Boolean = …
}
class Double {
def <(other: Double): Boolean = …
}
class String {
def <(other: String): Boolean = …
}
- 9. Общее поведение выделяется в
класс:
trait Ordered[A] {
def <(other: A): Boolean
…
}
class Int extends Ordered[Int] { … }
class Double extends Ordered[Double] { … }
class String extends Ordered[String] { … }
- 10. Проблема 1: не можем заранее
предугадать, какое поведение нам
понадобится:
class Int extends Ordered[Int]
with Addable[Int]
with Random[Int]
with ToJSON[Int]
with ToXML[Int]
with ToBinary[Int]
with …
- 11. Проблема 2: не всё общее
поведение можно выразить через
наследование
trait Zero[A] {
def zero: A
}
class Int extends Zero[Int] {
def zero = 0
}
Чтобы иметь возможность вызвать zero,
нужен экземпляр класса Int
???
- 13. Решение: классы типов
object intInstance
extends Addable[Int]
with Zero[Int] {
def add(a1: Int, a2: Int) = a1+a2
def zero = 0
}
object stringInstance
extends Addable[String]
with Zero[String] {
def add(s1: String, s2: String) = s1+s2
def zero = ""
}
- 18. scala> 3 === 3
res0: Boolean = true
scala> "s" /== "s2"
res1: Boolean = true
scala> 3 === "s"
<console>:14: error: type mismatch;
found : String("s")
required: Int
3 === "s"
^
- 19. scalaz.Order[A]
trait Order[A] extends Equal[A] {
def order(a1: A, a2: A): Ordering
def equal(a1: A, a2: A) =
order(a1, a2) == EQ
}
sealed trait Ordering
case object LT extends Ordering
case object EQ extends Ordering
case object GT extends Ordering
- 20. Принцип использования Scalaz:
Когда объявляем класс
class Rational(nom: Int, denom: Int) { … }
… в объекте-компаньоне создаём инстанс,
реализующий все необходимые классы типов:
object Rational {
implicit object instance
extends Order[Rational]
with Numeric[Rational]
with … {
def order(r1: Rational, r2: Rational) = …
…
}
}
- 21. scalaz.Enum[A]
trait Enum[A] extends Order[A] {
def succ(a: A): A
def pred(a: A): A
def fromToL(f: A, t: A): List[A] = …
}
implicit class EnumOps[A](a: A)
(implicit val e: Enum[A]) {
def |-> (to: A) = e.fromToL(a, to)
}
- 22. scala> 1 |-> 5
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> 'a' |-> 'd'
res1: List[Char] = List(a, b, c, d)
- 24. scala> 3 |+| 2
res0: Int = 5
scala> List(1,2,3) |+| List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> "abc" |+| "de"
res2: String = abcde
- 25. scala> List(1,2,3) ++ "ab"
res0: List[AnyVal] = List(1, 2, 3, a, b)
scala> List(1,2,3) |+| "ab"
<console>:26: error: type mismatch;
found : String("ab")
required: List[Int]
List(1,2,3) |+| "ab"
^
- 28. scala> sum(List(1,2,3))
res0: Int = 6
scala> sum(List("ab","cd","ef"))
res1: String = abcdef
scala> sum(List(List(1,2),List(3,4))
res2: List[Int] = List(1,2,3,4)
- 29. class List[A] {
def map[B](f: A => B): List[B]
}
class Vector[A] {
def map[B](f: A => B): Vector[B]
}
class Option[A] {
def map[B](f: A => B): Option[B]
}
- 30. class List[A] {
def map[B](f: A => B): List[B]
}
class Vector[A] {
def map[B](f: A => B): Vector[B]
}
class Option[A] {
def map[B](f: A => B): Option[B]
}
- 32. trait Functor[F[_]] {
def map[A,B](fa: F[A])(f: A => B): F[B]
}
implicit object listInstance =
new Functor[List] {
def map[A,B](fa: List[A])(f: A => B) =
fa.map(f)
}
- 33. val opt: Option[Int] = for {
i ← Some(2)
j ← Some(3)
} yield (i + j)
val list: List[(Int, Int)] = for {
i ← List(1,2,3)
j ← List(5,6)
} yield (i, j)
- 34. val opt: Option[Int] = for {
i ← Some(2)
j ← Some(3)
} yield (i + j)
val list: List[(Int, Int)] = for {
i ← List(1,2,3)
j ← List(5,6)
} yield (i, j)
- 35. trait Apply[F[_]] extends Functor[F] {
def apply2[A,B,C](fa: => F[A], fb: => F[B])
(f: (A,B) => C): F[C]
}
scalaz.Apply[F[_]]
- 36. scala> Apply[Option].apply2(x, y)(_ + _)
res0: Option[Int] = Some(5)
scala> Apply[List].apply2(List(1,2,3),
List(5,6))((_, _))
res1: List[(Int,Int)] = List((1,5),(1,6),
(2,5),(2,6),(3,5),(3,6))
- 37. val opt: Option[Int] = Some(5)
val list: List[String] = List("a")
val fut: Future[Double] = Future(3.5)
- 38. val opt: Option[Int] = Some(5)
val list: List[String] = List("a")
val fut: Future[Double] = Future(3.5)
- 41. class List[A] {
def flatMap[B](f: A => List[B]): List[B]
}
class Vector[A] {
def flatMap[B](f: A => Vector[B]): Vector[B]
}
class Option[A] {
def flatMap[B](f: A => Option[B]): Option[B]
}