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
9.5k
ラムダ式禁止おじさん 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
1.3k
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.3k
#Ubie 狂気の認知施策と選考設計
ntaro
13
14k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.2k
KotlinでSpring 完全理解ガイド #jsug
ntaro
6
3.6k
Kotlinでサーバサイドを始めよう!
ntaro
1
1k
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
2.9k
Kotlin Contracts #m3kt
ntaro
4
4.3k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
540
Other Decks in Programming
See All in Programming
Agent Skills Workshop - AIへの頼み方を仕組み化する
gotalab555
13
7.3k
米国のサイバーセキュリティタイムラインと見る Goの暗号パッケージの進化
tomtwinkle
1
340
猫の手も借りたい!ので AIエージェント猫を作って社内に放した話 Claude Code × Container Lambda の Slack Bot "DevNeko"
naramomi7
0
220
TROCCOで実現するkintone+BigQueryによるオペレーション改善
ssxota
0
110
AIによる開発の民主化を支える コンテキスト管理のこれまでとこれから
mulyu
3
2.1k
PJのドキュメントを全部Git管理にしたら、一番喜んだのはAIだった
nanaism
0
220
TipKitTips
ktcryomm
0
110
Amazon Bedrockを活用したRAGの品質管理パイプライン構築
tosuri13
5
900
今、アーキテクトとして 品質保証にどう関わるか
nealle
0
190
DSPy入門 Pythonで実現する自動プロンプト最適化 〜人手によるプロンプト調整からの卒業〜
seaturt1e
1
380
モジュラモノリスにおける境界をGoのinternalパッケージで守る
magavel
0
3.3k
Ruby x Terminal
a_matsuda
5
500
Featured
See All Featured
Being A Developer After 40
akosma
91
590k
Mind Mapping
helmedeiros
PRO
1
110
The untapped power of vector embeddings
frankvandijk
2
1.6k
Marketing to machines
jonoalderson
1
5k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
120
Why Our Code Smells
bkeepers
PRO
340
58k
Practical Orchestrator
shlominoach
191
11k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
460
Test your architecture with Archunit
thirion
1
2.2k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
300
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Technical Leadership for Architectural Decision Making
baasie
2
270
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!