Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ラムダ式禁止おじさん ver1.1 #Kotlin_Sansan
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Taro Nagasawa
December 13, 2016
Programming
9.8k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ラムダ式禁止おじさん ver1.1 #Kotlin_Sansan
第4回Kotlin勉強会 @ Sansan (
https://connpass.com/event/44710/
)で発表したスライドです。
Taro Nagasawa
December 13, 2016
More Decks by Taro Nagasawa
See All by Taro Nagasawa
Android開発者のための Kotlin Multiplatform入門
ntaro
0
1.8k
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.4k
#Ubie 狂気の認知施策と選考設計
ntaro
14
14k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.2k
KotlinでSpring 完全理解ガイド #jsug
ntaro
6
3.7k
Kotlinでサーバサイドを始めよう!
ntaro
1
1.1k
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
3.1k
Kotlin Contracts #m3kt
ntaro
4
4.5k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
590
Other Decks in Programming
See All in Programming
React Native에 현대적인 빌드 도구 더하기: Rollipop 구현기
leegeunhyeok
0
180
学びを記事・スライド・Xへ高速展開する― AI-assisted Learning Loopで回すコンテンツ生成術
ochtum
0
190
Materialが消えた日 〜真っ白なFlutterキャンバスにRenderObjectで絵を描く〜
umigishiaoi
0
140
小さなアプリを作って公開するまで
onozaty
0
110
クラウドゲーミングのパフォーマンス最適化に挑む / Cloud Gaming Performance Tuning
vivion
0
320
Inertia Rails: The One-Person Framework with React & Friends
skryukov
0
380
Seven New Principles of Software Engineering
yegor256
0
440
Engineering Biometric UX Across Android Versions | DroidKnights 2026
ryunen344
1
170
まずはコードより業務と向き合う:テーブル解体のためにPdMを呼んだ話
sakawe_ee
0
140
AI駆動開発4年目の現在地(『あなたはFDEになるべきか?』イベント資料)
kumaiu
0
130
PyConTW 2026 - AI Coding 不只是工具升級, 區域醫院醫療資訊系統協作開發與資訊團隊轉型實踐
cclai999
0
230
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
3
1.7k
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.2k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
560
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
Producing Creativity
orderedlist
PRO
348
41k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Large-scale JavaScript Application Architecture
addyosmani
516
110k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.8k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
480
Into the Great Unknown - MozCon
thekraken
41
2.8k
First, design no harm
axbom
PRO
2
1.4k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
600
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!