fuzyco
January 11, 2018
530

# Try Cats

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

January 11, 2018

## Transcript

3. ### \$BUTͱ͸ 4DBMB[ͷ಺෦෼྾ʹΑͬͯੜ·Εͨ ؔ਺ܕϓϩάϥϛϯά༻ͷ4DBMBϥΠϒϥϦ ɾ೥ࠒ஀ੜ ɾʹWϦϦʔε ɾݍ DBUFHPSZ ʹ༝དྷ ಡΜͩจݙ ɾೣ൪IUUQFFETJODPNIFSEJOHDBUTKB

ɾ4DBMB8JUI\$BUT

5. ### \$BUTWT4DBMB[ \$BUT ɾ৽͍͠σʔλܕ ɾ࣮༻্ඞཁͳશͯͷ൚༻ؔ਺ͷ࣮૷  ΞυϗοΫଟ૬ੑɺUSBJU JNQMJDJU ೣ൪ΑΓҾ༻ 4DBMB[ ɾ৽͍͠σʔλܕ

ɾඪ४Ϋϥεͷ֦ு 0QUJPO0QT -JTU0QT  ɾ࣮༻্ඞཁͳશͯͷ൚༻ؔ਺ͷ࣮૷  ΞυϗοΫଟ૬ੑɺUSBJU JNQMJDJU ಠश4DBMB[ΑΓҾ༻

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] = cats.Always@5212e1f5 // lazy valͷΑ͏ʹ஗ԆධՁ val z = Eval.later { println("Computing Z") math.random } // z: cats.Eval[Double] = cats.Later@33eda11
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] = cats.Always@5212e1f5 // lazy valͷΑ͏ʹ஗ԆධՁ val z = Eval.later { println("Computing Z") math.random } // z: cats.Eval[Double] = cats.Later@33eda11
10. ### &WBMʹΑΔ࠶ؼॲཧ def factorial(n: BigInt): BigInt = if(n == 1) n

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

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

Eval.now(n) } else { factorial(n - 1).map(_ * n) } factorial(50000).value // ࣮ߦ &WBMΛ༻͍ͨίʔυʹมߋ
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 // ... ελοΫΦʔόʔϑϩʔ͕ى͖Δ
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…… &WBMEFGFSϝιουΛ࢖ͬͯ͞ΒʹϦϑΝΫλϦϯά
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…… &WBMEFGFSϝιουΛ࢖ͬͯ͞ΒʹϦϑΝΫλϦϯά ਖ਼ৗऴྃ
16. ### &WBMʹΑΔ࠶ؼॲཧ &WBMEFGFSϝιου͸ԿΛ͍ͯ͠Δͷ͔ʁ 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<">Λฦ͢ܭࢉΛ஗Ԇ͍ͯ͠Δ τϥϯϙϦϯԽ͕ߦΘΕɺؔ਺͕਺चͭͳ͗ Ͱݺ͹Εͳ͘ͳΔ

20. ### ϞφυͬͯԿͳͷ͔ ϞφυΛඥղ͘Ωʔϫʔυ ɾϑΝϯΫλʔ 'VODUPS  ɾΞϓϦΧςΟϒϑΝϯΫλʔ "QQMJDBUJWF'VODUPS ͜ͷೋͭ͸ඞͣग़ͯ͘Δ Ϟφυͱ͸ɺ݁߹཯ͱಉҰ཯Λຬͨ͢࠷খݶͷ ϞφυίϯϏωʔλͷू·Γͷ͍ͣΕ͔Λ࣮૷ͨ͠΋ͷͰ͋Δɻ

ʁ ΧϥʔίοϓຊΑΓҾ༻

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] .... }
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.)
24. ### "QQMJDBUJWF'VODUPS "QQMJDBUJWF͸"QQMZʹ QVSFϝιου "'<"> Λ௥Ճ͍ͯ͠ΔܕΫϥε ϓϦϛςΟϒ஋Λ"QQMJDBUJWFܕʹม׵ͯ͠ɺ ଞͷ"QQMJDBUJWFͱ߹੒Ͱ͖Δɹ DBUTͷ7BMJEBUFE͸BQQMJDBUJWFGVODUPSΛܗ੒͢Δ 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͸ಉҰ཯Λຬͨ͢
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 <- hogeOption(1) b <- hogeOption(a) } yield (a + b) // Some(2) .POBE͸લͷ஋ʹґଘ͢ΔॲཧΛఏڙ͢ΔܕΫϥε /POFqBU.BQ G qBU.BQ H /POFqBU.BQ BG B qBU.BQ H qBU.BQ͸݁߹཯Λຬͨ͢
26. ### Ϟφυ·ͱΊ Ϟφυͱ͸ɺ݁߹཯ͱಉҰ཯Λຬͨ͢࠷খݶͷ ϞφυίϯϏωʔλͷू·Γͷ͍ͣΕ͔Λ࣮૷ͨ͠΋ͷͰ͋Δɻ DPNQPTF G QVSF G DPNQPTF QVSF G

G ಉҰ཯ /POFqBU.BQ G qBU.BQ H  /POFqBU.BQ BG B qBU.BQ H ݁߹཯ ஋ʹแ·Εͨ΋ͷʹରͯ͠ɺؔ਺ͷ࿈࠯Λ࣮ߦͰ͖Δ