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

Try Cats

fuzyco
January 11, 2018

Try Cats

Scalaの関数型ライブラリCatsをやってみた話です。

fuzyco

January 11, 2018
Tweet

More Decks by fuzyco

Other Decks in Technology

Transcript

  1. 5SZ$BUT


    View Slide

  2. ΞδΣϯμ
    w $BUTͱ͸
    w $BUTಠࣗͷϞφυ
    w $BUTΛ௨ֶͯ͠Μͩ͜ͱ

    View Slide

  3. $BUTͱ͸
    4DBMB[ͷ಺෦෼྾ʹΑͬͯੜ·Εͨ
    ؔ਺ܕϓϩάϥϛϯά༻ͷ4DBMBϥΠϒϥϦ
    ɾ೥ࠒ஀ੜ
    ɾʹWϦϦʔε
    ɾݍ DBUFHPSZ
    ʹ༝དྷ
    ಡΜͩจݙ
    ɾೣ൪IUUQFFETJODPNIFSEJOHDBUTKB
    ɾ4DBMB8JUI$BUT

    View Slide

  4. $BUTͷಛ௃
    ɾؔ਺ܕϓϩάϥϛϯάΛ࣮ݱ͢ΔͨΊͷ
    ๛෋ͳܕΫϥεͷఏڙ
    ɾIBTLFMMʹ͍࣮ۙ૷ &Rɺ4IPXͳͲ

    View Slide

  5. $BUTWT4DBMB[
    $BUT
    ɾ৽͍͠σʔλܕ
    ɾ࣮༻্ඞཁͳશͯͷ൚༻ؔ਺ͷ࣮૷
    ΞυϗοΫଟ૬ੑɺUSBJUJNQMJDJU

    ೣ൪ΑΓҾ༻
    4DBMB[
    ɾ৽͍͠σʔλܕ
    ɾඪ४Ϋϥεͷ֦ு 0QUJPO0QT -JTU0QT

    ɾ࣮༻্ඞཁͳશͯͷ൚༻ؔ਺ͷ࣮૷
    ΞυϗοΫଟ૬ੑɺUSBJUJNQMJDJU

    ಠश4DBMB[ΑΓҾ༻

    View Slide

  6. $BUTWT4DBMB[
    &JUIFSa
    7BMJEBUFE7BMJEBUJPO
    3FBEFS3FBEFS
    4UBUF4UBUF
    8SJUFS8SJUFS
    ɾ༻ҙ͞Ε͍ͯΔϝιου͕Ұ෦ҟͳΔ͕ɺ
    ಉ͡Α͏ͳσʔλܕ͕͋Δ

    View Slide

  7. $BUTಠࣗͷϞφυ
    ɾ&WBM

    View Slide

  8. &WBMϞφυ
    ධՁΛ੍ޚ͢Δσʔλܕ
    import cats.Eval
    // valͷΑ͏ʹఆٛ࣌ʹධՁ
    val x = Eval.now {
    println("Computing X")
    math.random
    }
    // Computing X
    // x: cats.Eval[Double]
    = Now(0.8724950064732552)
    // defͷΑ͏ʹৗʹධՁ
    val y = Eval.always {
    println("Computing Y")
    math.random
    }
    // y: cats.Eval[Double]
    = [email protected]
    // lazy valͷΑ͏ʹ஗ԆධՁ
    val z = Eval.later {
    println("Computing Z")
    math.random
    }
    // z: cats.Eval[Double]
    = [email protected]

    View Slide

  9. &WBMϞφυ
    ධՁΛ੍ޚ͢Δσʔλܕ
    x.value // first access
    // res9: Double = 0.8724950064732552
    x.value // second access
    // res10: Double = 0.8724950064732552
    y.value // first access
    // Computing Y
    // res11: Double = 0.8795680260041828
    y.value // second access
    // Computing Y
    // res12: Double = 0.5640213059400854
    z.value // first access
    // Computing Z
    // res13: Double = 0.5813583535421343
    z.value // second access
    // res14: Double = 0.5813583535421343
    import cats.Eval
    // valͷΑ͏ʹఆٛ࣌ʹධՁ
    val x = Eval.now {
    println("Computing X")
    math.random
    }
    // Computing X
    // x: cats.Eval[Double]
    = Now(0.8724950064732552)
    // defͷΑ͏ʹৗʹධՁ
    val y = Eval.always {
    println("Computing Y")
    math.random
    }
    // y: cats.Eval[Double]
    = [email protected]
    // lazy valͷΑ͏ʹ஗ԆධՁ
    val z = Eval.later {
    println("Computing Z")
    math.random
    }
    // z: cats.Eval[Double]
    = [email protected]

    View Slide

  10. &WBMʹΑΔ࠶ؼॲཧ
    def factorial(n: BigInt): BigInt =
    if(n == 1) n else n * factorial(n - 1)
    factorial(50000) // ࣮ߦ
    ຤ඌ࠶ؼͰͳ͍࠶ؼؔ਺

    View Slide

  11. &WBMʹΑΔ࠶ؼॲཧ
    def factorial(n: BigInt): BigInt =
    if(n == 1) n else n * factorial(n - 1)
    factorial(50000) // ࣮ߦ
    ຤ඌ࠶ؼͰͳ͍࠶ؼؔ਺
    ελοΫΦʔόʔϑϩʔ͕ى͖Δ
    factorial(50000)
    // java.lang.StackOverflowError
    // ...

    View Slide

  12. &WBMʹΑΔ࠶ؼॲཧ
    def factorial(n: BigInt): Eval[BigInt] =
    if(n == 1) {
    Eval.now(n)
    } else {
    factorial(n - 1).map(_ * n)
    }
    factorial(50000).value // ࣮ߦ
    &WBMΛ༻͍ͨίʔυʹมߋ

    View Slide

  13. &WBMʹΑΔ࠶ؼॲཧ
    def factorial(n: BigInt): Eval[BigInt] =
    if(n == 1) {
    Eval.now(n)
    } else {
    factorial(n - 1).map(_ * n)
    }
    factorial(50000).value // ࣮ߦ
    &WBMΛ༻͍ͨίʔυʹมߋ
    factorial(50000).value
    // java.lang.StackOverflowError
    // ...
    ελοΫΦʔόʔϑϩʔ͕ى͖Δ

    View Slide

  14. &WBMʹΑΔ࠶ؼॲཧ
    def factorial(n: BigInt): Eval[BigInt] =
    if(n == 1) {
    Eval.now(n)
    } else {
    Eval.defer(factorial(n - 1).map(_ * n))
    }
    factorial(50000).value // ࣮ߦ
    // res20: BigInt =
    //33473205095971448369154760940714864779127732……
    &WBMEFGFSϝιουΛ࢖ͬͯ͞ΒʹϦϑΝΫλϦϯά

    View Slide

  15. &WBMʹΑΔ࠶ؼॲཧ
    def factorial(n: BigInt): Eval[BigInt] =
    if(n == 1) {
    Eval.now(n)
    } else {
    Eval.defer(factorial(n - 1).map(_ * n))
    }
    factorial(50000).value // ࣮ߦ
    // res20: BigInt =
    //33473205095971448369154760940714864779127732……
    factorial(50000).value
    // res20: BigInt =
    //33473205095971448369154760940714864779127732……
    &WBMEFGFSϝιουΛ࢖ͬͯ͞ΒʹϦϑΝΫλϦϯά
    ਖ਼ৗऴྃ

    View Slide

  16. &WBMʹΑΔ࠶ؼॲཧ
    &WBMEFGFSϝιου͸ԿΛ͍ͯ͠Δͷ͔ʁ
    def defer[A](a: => Eval[A]): Eval[A] =
    new Eval.Defer[A](a _) {}
    sealed abstract class Defer[A](val thunk: () => Eval[A]) extends Eval[A] {
    def memoize: Eval[A] = Memoize(this)
    def value: A = evaluate(this)
    }
    &WBMΛฦ͢ܭࢉΛ஗Ԇ͍ͯ͠Δ
    τϥϯϙϦϯԽ͕ߦΘΕɺؔ਺͕਺चͭͳ͗
    Ͱݺ͹Εͳ͘ͳΔ

    View Slide

  17. $BUTΛษڧֶͯͯ͠Μͩ͜ͱ
    ಡΜͩจݙ
    ɾೣ൪IUUQFFETJODPNIFSEJOHDBUTKB
    ɾ4DBMB8JUI$BUT
    ֶͼ
    ɾϞφυͬͯԿͳͷ͔
    ɾ,MFJTMJɺ3FBEFSϞφυ
    ɾϞφυม׵ࢠ

    View Slide

  18. ϞφυͬͯԿͳͷ͔
    Ϟφυͱ͸ɺ݁߹཯ͱಉҰ཯Λຬͨ͢࠷খݶͷ
    ϞφυίϯϏωʔλͷू·Γͷ͍ͣΕ͔Λ࣮૷ͨ͠΋ͷͰ͋Δɻ
    ΧϥʔίοϓຊΑΓҾ༻

    View Slide

  19. ϞφυͬͯԿͳͷ͔
    Ϟφυͱ͸ɺ݁߹཯ͱಉҰ཯Λຬͨ͢࠷খݶͷ
    ϞφυίϯϏωʔλͷू·Γͷ͍ͣΕ͔Λ࣮૷ͨ͠΋ͷͰ͋Δɻ
    ʁ
    ΧϥʔίοϓຊΑΓҾ༻

    View Slide

  20. ϞφυͬͯԿͳͷ͔
    ϞφυΛඥղ͘Ωʔϫʔυ
    ɾϑΝϯΫλʔ 'VODUPS

    ɾΞϓϦΧςΟϒϑΝϯΫλʔ "QQMJDBUJWF'VODUPS

    ͜ͷೋͭ͸ඞͣग़ͯ͘Δ
    Ϟφυͱ͸ɺ݁߹཯ͱಉҰ཯Λຬͨ͢࠷খݶͷ
    ϞφυίϯϏωʔλͷू·Γͷ͍ͣΕ͔Λ࣮૷ͨ͠΋ͷͰ͋Δɻ
    ʁ
    ΧϥʔίοϓຊΑΓҾ༻

    View Slide

  21. Ϟφυ
    'VODUPS"QQMZ
    "QQMJDBUJWF'VODUPS.POBE
    DBUTʹ͓͍ͯɺ࣍ͷॱͰਐԽ͍ͯ͘͠

    View Slide

  22. 'VODUPS
    -JTU 0QUJPOͳͲʹରͯ͠ɺ
    แ·Εͨ஋ʹରͯ͠Ҿ਺ؔ਺Λద༻͢ΔॲཧΛఏڙ͢ΔܕΫϥε
    List(1, 2, 3).map(_ * 2) // List(2, 4, 6)
    Some(1).map(_ * 2) // Some(2)
    @typeclass trait Functor[F[_]] extends functor.Invariant[F] { self =>
    def map[A, B](fa: F[A])(f: A => B): F[B]
    ....
    }

    View Slide

  23. "QQMZ
    'VODUPSΛ֦ுͯ͠ɺ/ݸͷ'VODUPS஋ʹ/Ҿ਺ؔ਺Λ
    ద༻͢ΔॲཧΛఏڙ͢ΔܕΫϥε
    import cats.implicits._
    // implicit defͰ҉໧తʹmap2, map3͕ద༻͞ΕΔ
    (Some(1), Some(2)).mapN(_ + ) // Some(3)
    (Some(1), Some(2), Some(3)).mapN(_ * _ * _) // Some(6)
    (List("ha", "heh", "hmm"), List("?", "!", ".")) mapN {_ + _}
    // List(ha?, ha!, ha., heh?, heh!, heh., hmm?, hmm!, hmm.)

    View Slide

  24. "QQMJDBUJWF'VODUPS
    "QQMJDBUJWF͸"QQMZʹ
    QVSFϝιου "'
    Λ௥Ճ͍ͯ͠ΔܕΫϥε
    ϓϦϛςΟϒ஋Λ"QQMJDBUJWFܕʹม׵ͯ͠ɺ
    ଞͷ"QQMJDBUJWFͱ߹੒Ͱ͖Δɹ
    DBUTͷ7BMJEBUFE͸BQQMJDBUJWFGVODUPSΛܗ੒͢Δ
    1.pure[Option] // Some(1)
    // શͯͷΠϕϯτΛݕূ্ͨ͠Ͱɺ߹੒Λߦ͏
    val result = (valid[String, String]("event 1 ok") |@|
    invalid[String, String]("event 2 failed!") |@|
    invalid[String, String]("event 3 failed!")) map {_ + _ + _}
    // result: cats.data.Validated[String,String] = Invalid(event 2 failed!event 3 failed!)
    DPNQPTF G QVSF
    G
    DPNQPTF QVSF G
    G
    QVSF͸ಉҰ཯Λຬͨ͢

    View Slide

  25. .POBE
    "QQMJDBUJWF'VODUPS͸ෳ਺ͷ'VODUPS஋Λѻ͏͜ͱ͕Ͱ͖͕ͨɺ
    લͷ'VODUPS஋ʹґଘ͢ΔॲཧΛॻ͚ͳ͍ɻ
    def hogeOption(a: Int): Option[Int] = Some(a)
    hogeOption(1).flatMap(a => hogeOption(a).map(b => a+b))
    // Some(2)
    for {
    a b } yield (a + b)
    // Some(2)
    .POBE͸લͷ஋ʹґଘ͢ΔॲཧΛఏڙ͢ΔܕΫϥε
    /POFqBU.BQ G
    qBU.BQ H
    /POFqBU.BQ BG B
    qBU.BQ H


    qBU.BQ͸݁߹཯Λຬͨ͢

    View Slide

  26. Ϟφυ·ͱΊ
    Ϟφυͱ͸ɺ݁߹཯ͱಉҰ཯Λຬͨ͢࠷খݶͷ
    ϞφυίϯϏωʔλͷू·Γͷ͍ͣΕ͔Λ࣮૷ͨ͠΋ͷͰ͋Δɻ
    DPNQPTF G QVSF
    G
    DPNQPTF QVSF G
    G
    ಉҰ཯
    /POFqBU.BQ G
    qBU.BQ H

    /POFqBU.BQ BG B
    qBU.BQ H


    ݁߹཯
    ஋ʹแ·Εͨ΋ͷʹରͯ͠ɺؔ਺ͷ࿈࠯Λ࣮ߦͰ͖Δ

    View Slide