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
9k
ラムダ式禁止おじさん 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
680
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.2k
#Ubie 狂気の認知施策と選考設計
ntaro
13
13k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.1k
KotlinでSpring 完全理解ガイド #jsug
ntaro
6
3.4k
Kotlinでサーバサイドを始めよう!
ntaro
1
980
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
2.7k
Kotlin Contracts #m3kt
ntaro
4
4.1k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
500
Other Decks in Programming
See All in Programming
ASP.NETアプリケーションのモダナイズ インフラ編
tomokusaba
1
400
Cursor AI Agentと伴走する アプリケーションの高速リプレイス
daisuketakeda
1
120
SODA - FACT BOOK
sodainc
1
1.1k
エラーって何種類あるの?
kajitack
5
280
社内での開発コミュニティ活動とモジュラーモノリス標準化事例のご紹介/xPalette and Introduction of Modular monolith standardization
m4maruyama
1
130
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
3
840
すべてのコンテキストを、 ユーザー価値に変える
applism118
2
490
XSLTで作るBrainfuck処理系
makki_d
0
210
イベントストーミング図からコードへの変換手順 / Procedure for Converting Event Storming Diagrams to Code
nrslib
1
210
AWS CDKの推しポイント 〜CloudFormationと比較してみた〜
akihisaikeda
3
300
XP, Testing and ninja testing
m_seki
2
140
AIコーディング道場勉強会#2 君(エンジニア)たちはどう生きるか
misakiotb
1
240
Featured
See All Featured
Product Roadmaps are Hard
iamctodd
PRO
53
11k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Site-Speed That Sticks
csswizardry
10
650
Designing for humans not robots
tammielis
253
25k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
46
9.6k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
920
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.4k
A designer walks into a library…
pauljervisheath
206
24k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
Building Adaptive Systems
keathley
43
2.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!