Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ラムダ式禁止おじさん ver1.1 #Kotlin_Sansan
Search
Taro Nagasawa
December 13, 2016
Programming
4
8.6k
ラムダ式禁止おじさん ver1.1 #Kotlin_Sansan
第4回Kotlin勉強会 @ Sansan (
https://connpass.com/event/44710/
)で発表したスライドです。
Taro Nagasawa
December 13, 2016
Tweet
Share
More Decks by Taro Nagasawa
See All by Taro Nagasawa
Android開発者のための Kotlin Multiplatform入門
ntaro
0
370
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.1k
#Ubie 狂気の認知施策と選考設計
ntaro
13
12k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.1k
KotlinでSpring 完全理解ガイド #jsug
ntaro
6
3.3k
Kotlinでサーバサイドを始めよう!
ntaro
1
920
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
2.6k
Kotlin Contracts #m3kt
ntaro
4
3.8k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
430
Other Decks in Programming
See All in Programming
Pinia Colada が実現するスマートな非同期処理
naokihaba
4
230
Macとオーディオ再生 2024/11/02
yusukeito
0
370
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
120
Nurturing OpenJDK distribution: Eclipse Temurin Success History and plan
ivargrimstad
0
940
[Do iOS '24] Ship your app on a Friday...and enjoy your weekend!
polpielladev
0
110
受け取る人から提供する人になるということ
little_rubyist
0
230
役立つログに取り組もう
irof
28
9.6k
RubyLSPのマルチバイト文字対応
notfounds
0
120
見せてあげますよ、「本物のLaravel批判」ってやつを。
77web
7
7.8k
アジャイルを支えるテストアーキテクチャ設計/Test Architecting for Agile
goyoki
9
3.3k
3rd party scriptでもReactを使いたい! Preact + Reactのハイブリッド開発
righttouch
PRO
1
600
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
Featured
See All Featured
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
Optimising Largest Contentful Paint
csswizardry
33
2.9k
RailsConf 2023
tenderlove
29
900
Side Projects
sachag
452
42k
Faster Mobile Websites
deanohume
305
30k
GraphQLとの向き合い方2022年版
quramy
43
13k
Six Lessons from altMBA
skipperchong
27
3.5k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
0
96
The Cost Of JavaScript in 2023
addyosmani
45
6.8k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
6.9k
Raft: Consensus for Rubyists
vanstee
136
6.6k
Transcript
ラムダ式禁止おじさん 〜もうすぐver 1.1が来るバージョン〜 2016-12-13 第4回Kotlin勉強会@Sansan 長澤 太郎 @ngsw_taro
Kotlinってラムダ式使えて快適〜(^q^) list .filter { it % 3 == 0 }
.fold(0) { a, e -> a + e } .let { println(it) }
おじさん曰く
ラムダ式は 難しい! おじさん曰く
複数の文が入り込む余地があるのが... list .filter { hoge(); fuga(); piyo(); it % 3
== 0 } .fold(0) { a, e -> a + e } .let { println(it) }
ラムダ式なんか禁止だ〜〜〜〜〜!!! list .filter(myCondition) .fold(0, Int::plus) .let(::println)
トリにして ネタ枠 です
もくじ 1. 関数参照・メソッド参照 2. カリー化、関数の部分適用 3. Java的なメソッド参照 4. nullableどうするの問題 5.
まとめと注意事項
自己紹介 • 長澤 太郎 たろーって呼んでね ◦ @ngsw_taro • エンジニア@エムスリー株式会社 ◦
ITで医療を変革! ◦ Android, Kotlin, Java, Spring, Railsなど • Kotlinエバンジェリスト • ディズニーが好き
1. 関数参照・メソッド参照
引数を1つだけ取る関数 123.let { println(it) }
引数を1つだけ取る関数 123.let { println(it) } ここのラムダ式をなくしたい!
関数参照 val println: (Int) -> Unit = ::println 123.let(println) 123.let(::println)
関数参照 val println: (Int) -> Unit = ::println 123.let(println) 123.let(::println)
関数オブジェクトへの 参照を取得できる
関数参照 val println: (Int) -> Unit = ::println 123.let(println) 123.let(::println)
関数の型
関数参照 val println: (Int) -> Unit = ::println 123.let(println) 123.let(::println)
普通に引数として渡すだけ
関数参照 val println: (Int) -> Unit = ::println 123.let(println) 123.let(::println)
もちろん直接もOK!
引数を取らないメソッド "hoge".let { it.toUpperCase() }
引数を取らないメソッド "hoge".let { it.toUpperCase() } ここのラムダ式をなくしたい!
メソッド参照 val toUpperCase: String.()->String = String::toUpperCase "hoge".let(toUpperCase)
メソッド参照 val toUpperCase: String.()->String = String::toUpperCase "hoge".let(toUpperCase) 関数オブジェクトへの 参照を取得できる
メソッド参照 val toUpperCase: String.()->String = String::toUpperCase "hoge".let(toUpperCase) 関数の型
メソッド参照 val toUpperCase: String.()->String = String::toUpperCase "hoge".let(toUpperCase) レシーバの型
メソッド参照 val toUpperCase: String.()->String = String::toUpperCase "hoge".let(toUpperCase) 引数リスト->戻り型
メソッド参照 val toUpperCase: String.()->String = String::toUpperCase "hoge".let(toUpperCase) 普通に引数として渡すだけ
できたこと 123.let { println(it) } 123.let(::println) "hoge".let { it.toUpperCase() }
"hoge".let(String::toUpperCase)
2. カリー化、関数の部分適用
引数を2つ取る関数 fun minus(a: Int, b: Int) = a - b
3.let { minus(5, it) } //=> 2 ここのラムダ式をなくしたい!
デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:
A): (B) -> R = { this(a, it) }
デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:
A): (B) -> R = { this(a, it) } 「AとBを引数に取り、Rを返す関数」に 拡張関数invokeを生やす
デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:
A): (B) -> R = { this(a, it) } Aを引数に取り、 「Bを引数に取り、Rを返す関数」を返す
デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:
A): (B) -> R = { this(a, it) } 演算子オーバロードにより function2.invoke(foo) ↓ function2(foo)
デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:
A): (B) -> R = { this(a, it) } つまり、invoke関数の存在によって (A, B)->R を (A)->((B)->R) とも見なせる
デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:
A): (B) -> R = { this(a, it) } ※invokeはカリー化する関数ではありません。 ((A, B)->R)が1引数関数に見えるようにするための関数です。 あくまで「カリー化してるっぽく」見せているだけです。
minusを1引数関数として使える! fun minus(a: Int, b: Int) = a - b
(::minus)(5, 2) //=> 3 val x = (::minus)(5) x(2) //=> 3 (::minus)(5)(2) //=> 3
ラムダ式を消せる! 3.let { minus(5, it) } //=> 2 3.let((::minus)(5)) //=>
2
引数の位置を変えたい問題 5.let { minus(it, 3) } //=> 2 5.let((::minus)(3)) //=>
-2
関数の部分適用 5.let { minus(it, 3) } //=> 2 5.let((::minus)(3)) //=>
-2 5.let((::minus)(_, 3)) //=> 2 プレースホルダーを置いて、 引数の位置をコントロールしたい!
プレースホルダー enum class PlaceHolder { アレ }
プレースホルダーを取る拡張関数invoke operator fun <A, B, R> ((A, B) -> R).invoke(p:
PlaceHolder, b: B): (A) -> R = { this(it, b) }
プレースホルダーを取る拡張関数invoke operator fun <A, B, R> ((A, B) -> R).invoke(p:
PlaceHolder, b: B): (A) -> R = { this(it, b) } 「AとBを引数に取り、Rを返す関数」に 拡張関数invokeを生やす
プレースホルダーを取る拡張関数invoke operator fun <A, B, R> ((A, B) -> R).invoke(p:
PlaceHolder, b: B): (A) -> R = { this(it, b) } プレースホルダーとBを引数に取り、 「Aを取ってRを返す関数」を返す
1引数バージョンのminusを自在に使える (::minus)(5, 3) //=> 2 (::minus)(アレ, 3)(5) //=> 2
ラムダ式を消せる! 5.let { minus(it, 3) } //=> 2 5.let((::minus)(アレ, 3))
//=> 2
3. Java的なメソッド参照
レシーバが指定されたメソッド参照 // Javaコード static class Calculator { int succ(int x)
{ return x + 1; } } public static void main(final String... args) { final Calculator c = new Calculator(); Optional.of(5).map(c::succ); }
レシーバが指定されたメソッド参照 // Javaコード static class Calculator { int succ(int x)
{ return x + 1; } } public static void main(final String... args) { final Calculator c = new Calculator(); Optional.of(5).map(c::succ); } 「c」のsuccメソッド
一方、Kotlinは... class Calculator { fun succ(x: Int): Int = x
+ 1 } val calc = Calculator() 2.let(calc::succ) // NG 2.let { calc.succ(it) } // こう書くしか…?
T.(A)->Rは、(T, A)->Rでもある! class Calculator { fun succ(x: Int): Int =
x + 1 } val a: Calculator.(Int)->Int = Calculator::succ val b: (Calculator, Int)-> Int = a
T.(A)->Rは、(T, A)->Rでもある! class Calculator { fun succ(x: Int): Int =
x + 1 } val a: Calculator.(Int)->Int = Calculator::succ val b: (Calculator, Int)-> Int = a
つまり val calc = Calculator() 2.let(calc::succ) // NG 2.let {
calc.succ(it) } // OK 2.let { (Calculator::succ)(calc, it) } // OK
さらに val calc = Calculator() 2.let(calc::succ) // NG 2.let {
calc.succ(it) } // OK 2.let { (Calculator::succ)(calc, it) } // OK 2.let((Calculator::succ)(calc)) // OK
さらに val calc = Calculator() 2.let(calc::succ) // NG 2.let {
calc.succ(it) } // OK 2.let { (Calculator::succ)(calc, it) } // OK 2.let((Calculator::succ)(calc)) // OK 既にカリー化する方法を知っているので、 it を省略して、ラムダ式を消せる!
ちょっと待った!! class Calculator { fun succ(x: Int): Int = x
+ 1 } val calc = Calculator() 2.let(calc::succ) // NG 2.let { calc.succ(it) } // こう書くしか…?
ちょっと待った!! class Calculator { fun succ(x: Int): Int = x
+ 1 } val calc = Calculator() 2.let(calc::succ) // OK ver1.1から 2.let { calc.succ(it) } // こう書くしか…? ラムダ式禁止が捗るね!!
4. nullableどうするの問題
安全呼び出しするためには、ラムダ式が... setOf<Int?>(2).map { it?.let(::succ) } setOf<Int?>(2).map { it?.inc() }
安全呼び出しするためには、ラムダ式が... setOf<Int?>(2).map { it?.let(::succ) } setOf<Int?>(2).map { it?.inc() }
関数のnullable対応 fun <A, R> ((A) -> R).nullOk(): (A?) -> R?
= { it?.let(this@nullOk) }
関数のnullable対応 fun <A, R> ((A) -> R).nullOk(): (A?) -> R?
= { it?.let(this@nullOk) } 普通の関数を取って
関数のnullable対応 fun <A, R> ((A) -> R).nullOk(): (A?) -> R?
= { it?.let(this@nullOk) } 「nullableを取って、 nullableを返す関数」を返す
ラムダ式を消せる setOf<Int?>(2).map { it?.let(::succ) } setOf<Int?>(2).map { it?.inc() } setOf<Int?>(2).map(::succ.nullOk())
setOf<Int?>(2).map(Int::inc.nullOk())
5. まとめと注意事項
まとめ • 関数参照、メソッド参照により、スッキリしたコードが書ける • カリー化や関数の部分適用により、無理やり1引数関数の形 にして、ラムダ式を排除できる • Java的なメソッド参照のような記法は使えない。しかし、無理 やり1引数関数の形にして、ラムダ式を排除できる →ver1.1
から可能に! • notNullを取る関数を持ち上げて、無理やりnullableに対応さ せ、ラムダ式を排除できる
注意事項 • ラムダ式を使いましょう • 「単純な関数参照」はOK • ちょっと複雑な関数参照は、インライン展開されない場合が多 く、パフォーマンスに影響あり • わざわざトリッキーなコード書くな(怒)
Thank you Enjoy Kotlin!