Slide 2

Slide 2 text

whoami • ໊લ: Jun Sekine @jsoizo • Blog: https://jsoizo.hatenablog.com/ • ॴଐ: גࣜձࣾίυϞϯ • Server Side Kotlin͸͡Ίͯ3ϲ݄΄ͲͰ͢ • લ͸ScalaΛ͔͍ͭͬͯ·ͨ͠, akka͕޷͖Ͱͨ͠ • KotlinͰ͸Arrow.kt͕޷͖ • Ϟφυͱ͔͸Α͘Θ͔ΒΜͰ͢

Slide 3

Slide 3 text

Intro ScalaൺͰKotlin͸ग़དྷΔ͜ͱ͕͍͍ҙຯͰݶఆతͰஸ౓͍͍ͱײ͡·͢ɻ ҰํͰ഑ྻૢ࡞ʹ͓͍ͯScalaͩͱޮ཰ྑ͘=૸ࠪճ਺͕গͳ͘Ͱ͖Δ͜ͱ͕ɺ KotlinͩͱͰ͖ͣਏΈΛײͨ͜͡ͱ͕͋ΓextensionΛ࡞ͬͨͷͰ঺հ͠·͢ɻ • partitionMap = partition & map, partitionMap(Either൛) • collect = fi lter & map, collectFirst = fi nd & map • groupMapReduce = groupBy & reduce

Slide 4

Slide 4 text

partitionMap = partition & map partition͸഑ྻͷ֤ཁૉʹରͯ͠predicateΛ࣮ߦ͠ ݁Ռ͕trueͳΒPairͷ fi rst, falseͳΒsecondʹͳΔ͕ɺ patitionMap͸ fi rst, secondͷ஋ΛͦΕͧΕmapͨ݁͠ՌΛฦ٫͢Δɻ fun Iterable.partitionMap( predicate: (A) -> Boolean, transformFirst: (A) -> F, transformSecond: (A) -> S ): Pair, List> = this.fold(Pair(emptyList(), emptyList())) { acc, it -> val (fList, sList) = acc if (predicate(it)) Pair(fList, sList.plus(transformSecond(it))) else Pair(fList.plus(transformFirst(it)), sList) }

Slide 5

Slide 5 text

partitionMap (Either൛) transformͷ݁ՌΛArrow.ktͷEitherͱ͢Δ͜ͱͰɺ ScalaͷpartitionMapͱಉ͡γάωνϟͱ͍ͯ͠Δɻ ม׵݁ՌͷEither͕Leftͷ৔߹͸ fi rst, Rightͷ৔߹͸secondʹ٧ΊΔɻ EitherͰόϦσʔγϣϯΛ࣮૷͍ͯ͠ΔࡍͷҰׅॲཧͳͲͰศར ※ ͓ͦΒ͘kotlin-resultͷResultΛར༻ͯ͠΋ಉ͜͡ͱΛ࣮ݱͰ͖Δ͸ͣ fun Iterable.partitionMap( transform: (A) -> Either ): Pair, List> = this.fold(Pair(emptyList(), emptyList())) { acc, it -> val (fList, sList) = acc transform(it).fold({ Pair(fList.plus(it), sList) }, { Pair(fList, sList.plus(it)) })

Slide 6

Slide 6 text

partitionMap (Either൛) csvಡΈࠐΈ౳ʹΑΓෳ਺ͷΦϒδΣΫτΛҰׅͰੜ੒͠ɺ ͢΂ͯόϦσʔγϣϯ͕௨ͬͨ৔߹ͷΈอଘ͞ΕΔɺͱ͍͏ྫ data class PersonValidateError: DomainError data class Person private constructor(val name: String, val age: Int) { companion object { fun of(name: String, age: Int): Either } } data class Row(val col1: String, val col2: Int) val rows = listOf(Row("Alice", 20), Row("Bob", -2), Row("", 35)) val (errors, validatedPersons) = rows.partitionMap({ Person.of(it.col1, it.col2) }) // errors: List validatedPersons: List if (errors.isNotEmpty()) savePersons(validatedPersons)

Slide 8

Slide 8 text

collect = fi lter & map ഑ྻͷ֤ཁૉʹରͯ͠conditionΛ࣮ߦ͠ɺ ݁Ռ͕trueͷ৔߹͸ͦͷཁૉΛtransformʹ͔͚ͨ݁ՌΛฦ٫͢Δɻ ※ Scalaͷcollect͸Ҿ਺͕PartialFunction[A, B]ͳͷͰ΋ͬͱෳࡶͳ৔߹෼͚͕Մ (PartialFunction ≒ ࢦఆͨ͠৚݅ԼͰͷΈ஋Λฦ͢ύλʔϯϚον) Ώ͑ʹยखམͪײ͕൱Ίͣɺਖ਼௚mapNotNullͰे෼ͱײ͡Δ͜ͱ͕ଟ͍ fun Iterable.collect(condition: (A) -> Boolean, transform: (A) -> B): List = this.mapNotNull { if (condition(it)) transform(it) else null }

Slide 9

Slide 9 text

collect = fi lter & map ςετͷ఺਺Ϧετͷத͔Βӳޠͷ఺਺͚ͩΛநग़͠੔ܗ͢Δྫ val scores = listOf( Triple("Alice", "Math", 90), Triple("Alice", "English", 78), Triple("Bob", "Math", 50), Triple("Bob", "English", 80), ) val englishScoresPrettyPrinted = scores.collect( { it.second == "English" }, // condition: (T) -> Boolean { "${it.first} - ${it.third}఺" } // transform: (T) -> A ) // Alice - 78఺ // Bob - 80఺

Slide 10

Slide 10 text

collectFirstOrNull = collect & fi rstOrNull ഑ྻͷ֤ཁૉʹରͯ͠conditionΛ࣮ߦ͠ɺ ࠷ॳʹ݁Ռ͕trueʹͳͬͨཁૉΛtransformʹ͔͚ͯฦ٫͢Δɻ condition͕trueʹͳΔཁૉ͕ͳ͍৔߹͸nullΛฦ٫͢Δɻ fi nd{ condition(it) }?.let { transform(it) } ͱಉ༷ͱ΋͍͑Δɻ ͜Ε·ͨಉ༷ʹPartialFunction͕ͳ͍Ώ͑ fi rstNotNullOfOrNullͰࣄ଍ΓΔ͜ͱଟ͠… fun Iterable.collectFirstOrNull( condition: (A) -> Boolean, transform: (A) -> B ): B? = this.firstNotNullOfOrNull { if (condition(it)) transform(it) else null }

Slide 11

Slide 11 text

collectFirstOrNull = collect & fi rstOrNull ςετͷ఺਺Ϧετͷத͔Βӳޠͷ఺਺͚ͩΛ1͚ͭͩநग़͠੔ܗ͢Δྫ val scores = listOf( Triple("Alice", "Math", 90), Triple("Alice", "English", 78), Triple("Bob", "Math", 50), Triple("Bob", "English", 80), ) val emptyScores = emptyList> val englishScoresPrettyPrinted = scores.collectFirst( { it.second == "English" }, // condition: (T) -> Boolean { "${it.first} - ${it.third}఺" } // transform: (T) -> A ) // Alice - 78఺ // ಉ͡ॲཧΛemptyScoresʹରͯ͠ߦ͏ͱnull͕ฦ٫͞ΕΔ

Slide 12

Slide 12 text

Slide 13

Slide 13 text

groupMapReduce class ScoresRecord (val name: String, val kamoku: String, val season: String, val value: Int) val scores = listOf( ScoresRecord("Alice", "਺ֶ", "21೥্ظ", 100), ScoresRecord("Alice", "ӳޠ", "21೥্ظ", 100), ScoresRecord("Bob", "਺ֶ", "21೥্ظ", 100), ScoresRecord("Bob", "ӳޠ", "21೥্ظ", 100), … ) value class PositiveInt(val value: Int) { fun plus(other: PositiveInt) = PositiveInt(this.value + other.value) } val scoresPerNameKamoku = scores.groupMapReduce( { Pair(it.name, it.kamoku) }, // keyTransform: (T) -> K { PositiveInt(it.value) }, // valueTransform: (T) -> V { a1, a2 -> a1.plus(a2) } // valueReduce: (V, V) -> (V) )

Slide 14

Slide 14 text

Outro • ഑ྻͷޮ཰తͳૢ࡞Λ͢ΔಠࣗextensionΛ༻ҙ͓ͯ͘͠ͱɺΞϓϦ έʔγϣϯͷੑೳʹد༩Ͱ͖Δ • ޮ཰ΛٻΊΔϓϩάϥϜΛॻͨ͘Ίʹطଘͷ࣮૷Λௐ΂ͨΓ޻෉Λ͢ ΔաఔͰҾ͖ग़͠΋૿͑Δ • Kotlinͨͷ͍͠ʂʂʂʂ • Arrow.kt͸͍͍ͧ