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

Scalaで関数型 再入門

Scalaで関数型 再入門

よく遭遇する、Scala標準ライブラリだけだと大変なケースでも、
Catsを使うとうまく関心事を分離して、クリーンかつ拡張に対して頑強になることがあります。

このスライドでは、そういった場合のCatsの使い所について、初学者向けに解説をしています。

2019年7月26日のセプテーニ・オリジナルでの社内勉強会資料です。

25fb3e7054e52e524817044853c2d4c3?s=128

Taisuke Oe

July 26, 2019
Tweet

More Decks by Taisuke Oe

Other Decks in Programming

Transcript

  1. Taisuke Oe 2019/7 /26 ษڧձ@ηϓςʔχɾΦϦδφϧ ScalaͰؔ਺ܕ ࠶ೖ໳

  2. ࣗݾ঺հ Taisuke Oe / ຑ২ ହี Twitter: @OE_uia GitHub: @taisukeoe

    Septeni Original, Inc. ٕज़ΞυόΠβʔ ScalaMatsuri ࠲௕
  3. ຊ೔ֶͿ͜ͱ Catsͷ࢖͍ํ Catsͷ࢖͍ॴ CatsΛ࢖͏ϝϦοτ

  4. ຊ೔ͷ஫ҙࣄ߲ ʢͰ͖Δ͚ͩਖ਼֬͞ΛଛͳΘͳ͍Α ͏ʣɺ͋͑ͯ؆୯ͳ୯ޠͰઆ໌ͯ͠ ͍·͢ɻ ʮܕΫϥεʯ౳ͷ୯ޠʹ׳Ε͍ͯΔ ਓ͸ɺ೴಺ͰϚοϐϯάͯͩ͘͠͞ ͍

  5. Catsʁ

  6. Cats͕ఏڙ͢Δ΋ͷ ࣅͨੑ࣭Λ࣋ͭʮܕͷάϧʔϓʯ ʮܕͷάϧʔϓʯॴଐͷ൑ఆϩδοΫ ʮܕͷάϧʔϓʯ༻ͷ৽ͨͳߏจ ʮܕͷάϧʔϓʯͱ߹Θͤͯ࢖͍΍͢ ͍σʔλܕ

  7. Cats͕ఏڙ͢Δ΋ͷ(຋༁) ܕΫϥε ܕΫϥεΠϯελϯεͱɺͦͷಋग़ ܕΫϥε੍໿ʹجͮ͘৽ͨͳߏจ ܕΫϥεͱ߹Θͤͯ࢖͍΍͍͢σʔ λܕ

  8. Catsͷ࢖͍ํ build.sbt ʹҎԼͷ2ߦΛ௥Ճ Cats 1.6.1͸࠷৽stable൛ͰɺScala 2.11, 2.12ʹରԠɻ Scala 2.13Λ࢖༻͢Δ৔߹͸ɺCats 2.0.0-M4͕࠷৽

    scalacOptions += "-Ypartial-unification" libraryDependencies += "org.typelevel" %% "cats-core" % "1.6.1"
  9. Catsͷ࢖͍Ͳ͜Ζ

  10. Catsͷ࢖͍Ͳ͜Ζ ࠓճ͸Scala։ൃͰ͠͹͠͹ૺ۰͢ ΔɺҎԼͷ2ͭʹϑΥʔΧε͠·͢ ৞ΈࠐΈ ܭࢉͷ߹੒

  11. ৞ΈࠐΈ

  12. ৞ΈࠐΈ List(1, 2, 3).foldLeft(0)(_ + _) foldLeftͰݪ࢝తͳ৞ΈࠐΈ List[Int]ͷ৔߹͸୯७

  13. ৞ΈࠐΈ ͡Ό͋List[Either[Error, Int]]͸ʁ List[Future[Either[Error, Int]]]͸ʁ

  14. List[Either[Error, Int]] val eitherList: List[Either[Error, Int]] = List(Right(1), Right(2), Right(3))

    eitherList.foldLeft(Right(0):Either[Error, Int]) { case (Right(v1), Right(v2)) => Right(v1 + v2) case (Right(_), l @ Left(_)) => l case (l @ Left(_), _) => l } foldLeft಺Ͱɺཁૉܕͷߏ଄ͷ෼ղ͕ඞཁ ߏ଄͕ਂ͘ωετ͢Δ΄Ͳɺίʔυྔ͕૿͑Δɻ ࠶ར༻͠ʹ͘͘ͳΔɻ
  15. ೉໰͸෼ׂͤΑ

  16. ʮListͷ৞ΈࠐΈʯΛ෼ׂ List(1, 2, 3).foldLeft(0)(_ + _) ଍͠ࢉ …… (_ +

    _) ۭͷ஋ …… 0 ৞ΈࠐΈํ …… foldLeft
  17. ଍͠ࢉ 1 + 1 = 2 “A” + “B” =

    “AB”
  18. ଍͠ࢉ Either[Error, Int]ܕ ͷ଍͠ࢉʹ͸ɺߏ଄ͷ ෼ղ͕ඞཁ Right(1) + Right(2) / /

    Right(3) ੒ޭ஋Int͕ɺ஋Ϋϥε(ྫ: Price)ʹมΘͬ ͯ΋ɺ࠶ར༻͍ͨ͠
  19. Don’t Repeat Yourself

  20. ʮ଍͠ࢉʯͷ࠶ར༻ Either[Error, Int]ͷ଍͠ࢉ Right(1) + Right(2) / / Right(3) T͕଍͠ࢉͰ͖Ε͹ɺEither[?

    , T]΋ ଍͠ࢉͰ͖ͦ͏ͩͧ……
  21. ͦ͜ͰCatsͷखΛआΓΑ͏

  22. Catsͷʮܕͷάϧʔϓʯ ڞ௨ͷੑ࣭Λݩʹʮܕͷάϧʔϓʯ͕ ఆٛ͞Ε͍ͯΔ ଍͠ࢉՄೳͳ΋ͷΛ·ͱΊͨɺʮܕ ͷάϧʔϓʯ΋ఆٛ͞Ε͍ͯΔ ͦΕ͕ʮSemigroupʯ΍ʮMonoidʯ

  23. Semigroup ʮܕͷάϧʔϓʯͷҰछ ʮ2ͭͷ஋Λ1ͭʹ·ͱΊΒΕΔʯ ࠓճͷ৔߹Ͱ͍͑͹ɺʮ଍͠ࢉʯ ந৅ϝιου͸ɺ`combine`

  24. Semigroup (຋༁) ܕΫϥεͷҰछ ೋ߲ԋࢉͰ͖Δ ݁߹ଇ(Associative Law)Λຬͨ͢ (A |+| B) |+|

    C = A |+| (B |+| C) ந৅ϝιου͸ɺ`combine`
  25. Semigroupͷ࢖͍ํ import cats._ import cats.implicits._ 1 |+| 2 // 3

    Option(1) |+| Option(2) // Some(3) (Right(1): Either[Error, Int]) |+| (Right(2): Either[Error, Int]) // Right(3)
  26. Semigroupͷ໾ׂ ͜ͷʮܕͷάϧʔϓʯʹՃೖͯ͠Δܕʹɺ `|+|` ͱ͍͏ߏจʢϝιουʣΛ௥Ճ͢Δ ͋ΔܕT͕ʮʰ଍͠߹ΘͤΒΕΔʱอূʯ ΛɺTʹର͢Δ੍໿ͱͯ͠දݱͰ͖Δ T: Semigroup

  27. Catsͷݡ͍ͱ͜Ζ ܕT͕ɺ͋Δʮܕͷάϧʔϓʯʹଐ͍ͯ͠Δอ ূΛ΋ͱʹɺTͷ೿ੜܕͷॴଐΛ൑ఆͰ͖Δ Int͸SemigroupʹՃೖͯ͠Δ Option[T]͸ɺT͕SemigroupͳΒɺOption[T] ΋Semigroupʹଐ͢Δ

  28. Catsͷݡ͍ͱ͜Ζ(຋༁) ͋ΔܕΫϥεΠϯελϯε͔Βɺଞͷܕʹର ͢ΔܕΫϥεΠϯελϯεΛಋग़Ͱ͖Δ Semigroup[Int]ܕͷ҉໧ͷ஋͕ఆٛ͞Εɺε ίʔϓʹ͋Δ Semigroup[Option[T]]͸ɺSemigroup[T]ܕͷ҉ ໧ͷ஋͔Βಋग़Մೳɻ

  29. Semigroup T͕SemigroupͷʮܕͷάϧʔϓʯʹೖΔ৚݅ Semigroup[T]ܕͷ҉໧ͷ஋͕͋Δ valͰ΋defͰ΋OK Scalaඪ४ϥΠϒϥϦ಺ͷܕ͸ɺCatsఏڙͷ҉໧ͷ ஋Λͦͷ··࢖͑͹ok `import cats.implicits._` ͢Ε͹શ෦ೖΔ

  30. Semigroup[T]ͷ஋ ͜͏͍͏΋ͷ͕Cats಺ʹେྔʹఆٛ͞ ΕͯΔʢ࣮ࡍʹ͸΋ͬͱෳࡶʣ implicit val semigroupInt: Semigroup[Int] = ??? implicit

    def semigroupEither[L,R](implicit E:Semigroup[R]): Semigroup[Either[L,R]] = ???
  31. Semigroup Tܕʹରͯ͠ɺSemigroup༻ͷߏจΛݺͼग़͢ํ๏ Catsʹఆٛ͞Ε͍ͯΔsyntaxΛimport͢Δ Implicit parameterͰɺSemigroup[T]ܕͷ҉໧ͷ ஋Λཁٻ͢Δ `import cats.implicits._` ͢Ε͹શ෦είʔϓʹೖ Δ

  32. Semigroupͷྫ String Int Double Option[T] ୠ͠T: Semigroup Either[A, B] ୠ͠B:

    Semigroup List[T] Map[K, V] ୠ͠V: Semigroup
  33. ٳܜ: Semigroupͷམͱ݀͠

  34. ͳͥʁ import cats._, cats.implicits._ Some(1) |+| Some(2)

  35. ݪҼ͸Semigroupͷ ܕύϥϝʔλ trait Semigroup[T] { def combine(t1: T, t2: T):

    T }
  36. Semigroup[T] ͸ ෆม Semigroup[T]ͷɺ T͸ෆม combineϝιουͷγάωνϟͷɺڞม ϙδγϣϯͱ൓มϙδγϣϯͷ྆ํʹT ग़ͯ͘Δ Ώ͑ʹɺSemigroup[Option[T]]͸ɺ Semigroup[Some[T]]ͱͯ͠͸࢖͑ͳ͍……

  37. OptionܕΛฦ͢.some import cats._ import cats.implicits._ 1.some |+| 2.some //Some(3) 1.some

    |+| none //Some(1) 1.asRight[Error] |+| 2.asRight[Error] //Right(3)
  38. ʮListͷ৞ΈࠐΈʯΛ෼ׂ ଍͠ࢉ => Semigroup ۭͷ஋ ৞ΈࠐΈํ

  39. ۭͷ஋ ܕʢͱͦͷೋ߲ԋࢉʣ͝ͱʹܾΊΔ͜ͱ͕Ͱ͖ͦ ͏ɻྫ͑͹ʮ଍͠ࢉʯͷ৔߹ɿ IntͳΒ0 StringͳΒ”” OptionͳΒNone Either[Error, Int]ͳΒɺRight[Error, Int](0)

  40. Monoid ʮܕͷάϧʔϓʯͷҰछ ʮ2ͭͷ஋Λ1ͭʹ·ͱΊΒΕΔʯˍʮۭ ͷ஋ΛఆٛͰ͖Δʯ શͯͷMonoid͸ɺSemigroupͰ΋͋Δʂ ந৅ϝιου͸ɺ`combine` ͱ `empty`

  41. Monoidͷྫ String Int Double Option[T] T: Semigroup Either[A, B] B:

    Monoid List Map[K, V] V: Semigroup
  42. ʮListͷ৞ΈࠐΈʯΛ෼ׂ ଍͠ࢉ => Monoid ۭͷ஋ => Monoid ৞ΈࠐΈํ

  43. ৞ΈࠐΈํ MonoidΛ࢖ͬͯͨͨΈࠐ·͍ͤͨ FoldableΛ࢖͍·͠ΐ͏

  44. Foldable ʮܕͷάϧʔϓʯͷҰछ ʮ৞ΈࠐΈͰ͖Δʯ ந৅ϝιου͸ `foldLeft` ͱ `foldRight`

  45. Foldableͷྫ List Option Vector Stream Map΍Set͸FoldableͰ͸͋Γ·ͤΜ

  46. Foldableͷ࢖͍ํ Ͱ͸Intͷ୅ΘΓʹɺಠࣗఆٛͷΫϥ εΛ࢖͍͍ͨ৔߹͸…? import cats._, cats.implicits._ Foldable[List].fold(List(1,2,3)) // 6 Foldable[List].fold(List(1.asRight[Error],

    2.asRight[Error])) // Right(3) Foldable[List].fold(List(1.asRight[Error], MyError().asLeft[Int])) // Left(MyError)
  47. ஋Ϋϥε Price case class Price(private val value: Int) extends AnyVal

    { def +(p: Price): Price = this.copy(value = value + p.value) } implicit val priceMonoid: Monoid[Price] = new Monoid[Price] { override def empty: Price = Price(0) override def combine(x: Price, y: Price): Price = x + y } import cats._, cats.implicits._ Foldable[List].fold( List(Price(100).asRight[Error], Price(200).asRight[Error]) ) //Price(300)
  48. ʮListͷ৞ΈࠐΈʯΛ෼ׂ ଍͠ࢉ => Monoid ۭͷ஋ => Monoid ৞ΈࠐΈํ => Foldable

  49. ͲͪΒ͕ྑ͍ʁ(૯ׅ) list.foldLeft ͱ Foldable[List].fold(list)

  50. ඪ४ foldLeftͷಛ௕ list.foldLeft ॳظ஋΍଍͠߹Θͤํ͕ॊೈ ຊདྷϞσϧԽ͢΂͖ϩδοΫ͕ฆΕࠐΉڪΕ͕͋Δ ෳࡶͳཁૉܕʹ͍ͭͯ͸ɺߏ଄ͷ෼ղΛఆٛ͢Δඞཁ ͕͋Δɻ ඪ४ʹ༻ҙ͞Ε͍ͯΔɻ ϥΠϒϥϦ(Cats)Λ࢖Θͳͯ͘΋ྑ͍

  51. Foldable[List].fold(list) ॳظ஋΍଍͠߹Θͤํ͕ɺMonoidͰܾ· Δ ؔ৺ࣄͷ෼཭Λڧ੍͢Δ ཁૉܕ͕ωετͨ͠ܕͰ͋ͬͯ΋ɺ߹੒ ʹΑΔ଍͠߹Θͤํ͕Ͱ͖Δ Foldable.foldͷಛ௕

  52. Foldable + Monoid ·ͱΊ ʮ଍͠߹Θͤํʯʮۭͷ஋ʯʮ৞Έ ࠐΈํʯʹର͢Δؔ৺͕ɺͦΕͧΕ ผͷܕʹ෼཭Ͱ͖Δɻ ωετͨ͠ܕͷʮ଍͠߹ΘͤํʯΛɺ ࣗಈతʹಋग़Ͱ͖Δɹ

  53. ٳܜ: Foldableͷམͱ݀͠

  54. ͳͥFoldableΦϒδΣΫτ ͷϝιουΛ࢖͏ʁ import cats._, cats.implicits._ Foldable[List].fold( List(Price(100).asRight[Error], Price(200).asRight[Error]) ) //Price(300)

  55. A. Listͷfoldϝιουͱ িಥ͢Δ͔Β def myFold[F[_]: Foldable, A: Monoid](list: F[A]): A

    = list.fold ͳΒ͹OKʢF͸ListͰ͸ͳ͍)
  56. ܭࢉͷ߹੒

  57. ܭࢉͱ͍͑͹ Future List Map Either

  58. Futureͷ߹੒ ͱ͍͑͹ɺforࣜ ௚ྻ࣮ߦ͍ͨ࣌͠ ฒྻ࣮ߦ͍ͨ࣌͠

  59. Լ४උ trait Product case class GoodProduct(id: Long, price: Price) extends

    Product case class NiceProduct(id: Long, price: Price) extends Product trait ProductRepository[F[_], T <: Product] { def resolveById(id: Long): F[T] } val goodRepo = new ProductRepository[Future, GoodProduct]{ override def resolveById(id: Long): Future[GoodProduct] = ??? } val niceRepo = new ProductRepository[Future, NiceProduct]{ override def resolveById(id: Long): Future[NiceProduct] = ??? } def taxing(product: Product): Future[Price] = ???
  60. Futureͷ߹੒: ௚ྻ FutureΠϯελϯεͷੜ੒͕ɺଞͷFutureͷܭࢉ݁Ռʹґଘ ͍ͯ͠Δ৔߹ forࣜͰ؆୯ʹ߹੒Ͱ͖Δɻ val taxedPrice = for {

    product <- goodRepo.resolveById(1L) taxed <- taxing(product) } yield taxed ͋Δ঎඼ͷՁ֨(੫ࠐ)Λܭࢉ
  61. Futureͷ߹੒: ฒྻ ߹੒͞ΕΔFutureಉ࢜ʹɺґଘؔ܎͕ͳ͍৔߹ Future͸Πϯελϯεੜ੒࣌ʹධՁ͕࢝·Δɻforࣜͷ֎Ͱ FutureΛੜ੒͠ͳ͚Ε͹ͳΒͳ͍ͷ͕໽հɻ val niceF = niceRepo.resolveById(2L) val

    sumOfPrice = for { good <- goodRepo.resolveById(1L) nice <- niceF } yield good.price + nice.price ෳ਺ͷ঎඼ͷՁ֨(੫ൈ)Λ߹ܭ͢Δɻ
  62. ෳ਺ͷ௚ྻܭࢉΛฒྻʹ ՄೳͳݶΓฒྻʹ߹੒ͯ͠ΈΔ val niceF = niceRepo.resolveById(2L) val both = for

    { good <- goodRepo.resolveById(1L) taxedGoodF = taxing(good) nice <- niceF taxedNice <- taxing(nice) taxedGood <- taxedGoodF } yield taxedGood + taxedNice ෳ਺ͷ঎඼ͷՁ֨(੫ࠐ)Λ߹ܭ͢Δɻ
  63. ෳ਺ͷ௚ྻܭࢉΛฒྻʹ forࣜΛ෼ׂ͢Δͱɺز෼Ϛγɻ val taxedGood = for { product <- goodRepo.resolveById(1L)

    taxed <- taxing(product) } yield taxed val taxedNice = for { product <- niceRepo.resolveById(2L) taxed <- taxing(product) } yield taxed for { goodPrice <- taxedGood nicePrice <- taxedNice } yield goodPrice + nicePrice ෳ਺ͷ঎඼ͷՁ֨(੫ࠐ)Λ߹ܭ͢Δɻ
  64. forࣜ ʮલͷܭࢉ݁Ռʹґଘ͢Δ(௚ྻ)ܭ ࢉʯͷ߹੒ʹศརɻ ʮґଘؔ܎͕ͳ͍(ฒྻ)ܭࢉʯΛ߹੒ ͢Δʹ͸ෆ޲͖ɻ

  65. forࣜ forࣜ͸ɺͦ΋ͦ΋ʮ௚ྻͨ͠ܭࢉʯ ͷͨΊͷߏจͰ͋Δ ͜ͷʮ௚ྻͨ͠ܭࢉʯΛද͢ʮܕͷ άϧʔϓʯʹɺCatsͰ͸Monadͱ͍͏ ໊લΛ͚͍ͭͯΔ

  66. Monad ʮܕͷάϧʔϓʯͷҰछ ʮ௚ྻͨ͠ܭࢉʯΛද͢ ந৅ϝιου: `flatMap`, `pure`, `tailRecM` `flatMap`͸Monadͷ߹੒

  67. Monadͷྫ Either List Option Future (˞ MonadଇΛຬ͍ͨͯ͠ͳ͍͕ɺCatsͰ͸Monadѻ͍)

  68. Applicative ʮܕͷάϧʔϓʯͷҰछ ʮґଘؔ܎͕ͳ͍ɺฒྻͨ͠ܭࢉʯΛ ද͢ ந৅ϝιου: `ap` ͱ `pure` શͯͷMonad͸ApplicativeͰ΋͋Δ

  69. Applicativeͷྫ Either List Option Future (˞ ApplicativeଇΛຬ͍ͨͯ͠ͳ͍͕ɺCatsͰ͸Applicativeѻ͍)

  70. ฒྻܭࢉΛ߹੒ ApplicativeελΠϧͰ͸ฒྻܭࢉΛ߹੒͠΍͍͢ import cats._ import cats.implicits._ (goodRepo.resolveById(1L).flatMap(taxing), niceRepo.resolveById(2L).flatMap(taxing)).mapN(_ + _)

    ෳ਺ͷ঎඼ͷՁ֨(੫ࠐ)Λ߹ܭ͢Δɻ Applicative[Future].map2( goodRepo.resolveById(1L).flatMap(taxing), niceRepo.resolveById(2L).flatMap(taxing))(_ + _)
  71. ฒྻܭࢉΛ߹੒ ฒྻͯ͠औಘ/ݕূͨ͠ܭࢉΛɺϑΝΫτϦϝ ιουʹ؆୯ʹྲྀ͠ࠐΊΔ import cats._ import cats.implicits._ case class User(name:

    String, age: Int) val nameFuture: Future[String] = ??? val ageFuture: Future[Int] = ??? (nameFuture, ageFuture).mapN(User.apply)
  72. ͜͜ͰRepositoryͷվम ΤϥʔΛEitherܕͰදݱ͢Δ͜ͱʹͳͬͨ Ͳ͏͢Ε͹ܭࢉ݁ՌΛ߹੒Ͱ͖Δʁ type EitherE[T] = Either[Error, T] type FutureEitherE[T]

    = Future[EitherE[T]] val goodERepo = new ProductRepository[FutureEitherE, GoodProduct]{ override def resolveById(id: Long): FutureEitherE[GoodProduct] = ??? } val niceERepo = new ProductRepository[FutureEitherE, NiceProduct]{ override def resolveById(id: Long): FutureEitherE[NiceProduct] = ??? }
  73. ApplicativeͱMonadͷҧ͍ Applicative͸ੵΈ্͛Մೳ FutureͷApplicativeͱɺEitherͷ Applicative͔ΒɺFuture[Either[….]]ͷ Applicative͕ಘΒΕΔ Monad͸ੵΈ্͕͛(ͦͷ··Ͱ͸)ෆՄೳ

  74. ApplicativeͱMonadͷҧ͍ Applicative[Future].compose[EitherE].map2( goodERepo.resolveById(1L), niceERepo.resolveById(2L))(_.price + _.price) Applicative[Future].compose[EitherE].map2( goodERepo.resolveById(1L).flatMap(taxing), niceERepo.resolveById(2L).flatMap(taxing))(_ +

    _) ίϯύΠϧͰ͖Δ ੫ۚͷܭࢉΛ͢ΔͱɺίϯύΠϧͰ͖ͳ͍ Monadͷ߹੒(flatMap)ͰίϯύΠϧΤϥʔ
  75. Monad Transformer Monad͕߹੒Ͱ͖ͳ͍͜ͱΛճආ͢ ΔͨΊͷ΋ͷ ੵΈ্͛ͨMonadΛϥοϓͯ͠ɺผ ͷMonadʹͯ͠͠·͏

  76. EitherT[Future, A, B] type EitherTFuture[T] = EitherT[Future, Error, T] val

    goodETRepo = new ProductRepository[EitherTFuture, GoodProduct] { override def resolveById(id: Long): EitherTFuture[GoodProduct] = ??? } val niceETRepo = new ProductRepository[EitherTFuture, NiceProduct] { override def resolveById(id: Long): EitherTFuture[NiceProduct] = ??? }
  77. EitherT[Future, A, B] Applicative[EitherTFuture].map2( goodETRepo.resolveById(1L).flatMap(taxing), niceETRepo.resolveById(2L).flatMap(taxing))(_ + _) EitherT͸Monadɻ શͯͷMonad͸ApplicativeͰ΋͋ΔͷͰɺEitherT͸ApplicativeͰ

    ΋͋Δɻ Ͱ΋taxingͷγάωνϟ͕ҰகͤͣɺίϯύΠϧͰ͖ͳ͍ def taxingEF(product: Product): EitherTFuture[Price] = ??? EitherTFuture൛ͷtaxing͕ཉ͍͠
  78. EitherT Future൛ ׬੒! val taxingEF = ɹɹ (taxing _).andThen(f =>

    EitherT(f.map(_.asRight[Error]))) Applicative[EitherTFuture].map2( goodETRepo.resolveById(1L).flatMap(taxingEF), niceETRepo.resolveById(2L).flatMap(taxingEF))(_ + _) ࠓճͷtaxingͷΑ͏ͳɺMonadΛฦؔ͢਺Λ ߹੒ɾ֦ு͍ͨ͠
  79. Kleisli Kleisli[F, A, B] ͸ A => F[B] ͷϥούʔ MonadΛੜ੒͢Δؔ਺Λϥοϓ͢Δ͜ͱ͕ଟ͍

    ͜ͷΑ͏ͳؔ਺Λศརʹѻ͏ͨΊͷϝιου͕ଟ ਺ɻ runϝιουͰɺதͷA => F[B]΁ΞΫηεՄೳ F͕MonadͰ͋Ε͹ɺKleisli[F, A, B]΋Monad
  80. Kleisli ߹੒ def taxing(product: Product): Future[Price] = ??? def exchange(jpy:

    Price): Future[PriceInUSD] = ??? // Function1ͷandThenʹΑΔ߹੒͸Ͱ͖ͳ͍ɻίϯύΠϧΤϥʔɻ // (taxing _) andThen exchange val taxingPriceInUSD = Kleisli(taxing) andThen exchange _ val taxingEFinUSD = taxingInUSD.mapF(f => EitherT(f.map(_.asRight[Error]))) Applicative[EitherTFuture].map2( goodETRepo.resolveById(1L).flatMap(taxingEFinUSD.run), niceETRepo.resolveById(2L).flatMap(taxingEFinUSD.run))(_ + _)
  81. Monad ͱ Applicative·ͱΊ forࣜ(Monadͷ߹੒)͸௚ྻʹܭࢉΛ߹੒͢Δ࣌༗ ༻ɻApplicative͸ɺຊདྷฒྻʹͰ͖Δܭࢉʹର͠ ༗༻ɻ ՄೳͳݶΓApplicative styleͷ߹੒ʹ͓ͯ͘͠ɻ͢ ΔͱܕͷੵΈ্͛౳ʹର͠ରԠ͠΍͍͢ɻ MonadͷੵΈ্͛ʹ͸ɺMonadTransformer͕༗ޮ

    ʢୠ͠2ஈ·Ͱ)
  82. ґଘ͕ͳͯ͘΋௚ྻ࣮ߦ Monadͷ߹੒(flatMap)͸ɺ௚ྻܭࢉ ʮલͷܭࢉ݁Ռʹґଘʯ͍ͯ͠ͳͯ͘΋ɺ ௚ྻʹ࣮ߦ͍ͨ͠έʔε ෭࡞༻Λॱ൪ʹى͍ͨ͜͠ ಉ࣌઀ଓ਺੍ݶͷ͋ΔAPI call

  83. ࠶ͼ৞ΈࠐΈ΁

  84. Foldable .foldMapM Monadͷ߹੒(flatMap)͸ɺ௚ྻܭࢉ ʮલͷܭࢉ݁Ռʹґଘʯ͍ͯ͠ͳͯ͘΋ɺ ௚ྻʹ࣮ߦ͍ͨ͠έʔε ෭࡞༻Λॱ൪ʹى͍ͨ͜͠ ಉ࣌઀ଓ਺੍ݶͷ͋ΔAPI call

  85. Foldable .foldMapM List(1L, 2L, 3L).foldMapM( goodETRepo.resolveById _ andThen (_.map(_.price)) )

    Repository͔ΒͷGoodProductऔಘ͕௚ྻ࣮ ߦ͞ΕΔ
  86. Future.sequenceͷҰൠԽ List[Either[Error, Price]] ͔ΒEither[Error, List[Price]]ΛಘΒΕͳ͍͔ʁ ඪ४ͷ Future.sequenceͷΑ͏ͳ΋ͷ

  87. ࣗྗͰsequence val sequenced: Either[Error, List[Price]] = list.foldRight(List.empty[Price].asRight[Error]){ (e, acc) =>

    for { value <- e valueList <- acc } yield value :: valueList } ґଘؔ܎ͷͳ͍(ฒྻ)ܭࢉ͕ొ৔͢Δɻ Applicativeͷ೏͍……
  88. Traverse ʮܕͷάϧʔϓʯͷҰछ ʮ൓෮ͱɺసஔʯΛͰ͖Δ Traverse͸ɺશͯFoldableͰ͋Δ ཁૉܕ͕Applicativeͷ࣌ɺsequence΍ traverse͕Ͱ͖Δ

  89. Traverseͷྫ List Option Vector Stream

  90. Traverse.sequence val list = List(Price(100).asRight[Error], Price(200).asRight[Error]) list.sequence // Right(List(Price(100), Price(200)))

    ೖΕସ͑੒ޭʂ
  91. ຊ೔ֶΜͩ͜ͱ Catsͷجຊతͳ࢖͍ํ ؔ਺ܕ༝དྷͷʮܕͷάϧʔϓʯͷ࢖͍ॴ ʮܕͷάϧʔϓʯͰɺؔ৺Λ෼཭͢Δํ ๏

  92. ͞ΒʹֶͿʹ͸ ʮܕͷάϧʔϓʯ͸ɺҰൠతͳ୯ޠͰ͸͋Γ·ͤΜɻ ຊདྷ ܕΫϥε ͱݺ͹Ε·͢ɻ ܕΫϥε ʹ͍ͭͯɺཧղΛਂΊΔʹ͸ҎԼͷࢿྉ Λࢀর͍ͯͩ͘͠͞ɻ Cats |

    Documentation Scalaʹ͓͚ΔܕΫϥεೖ໳