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
Taro Nagasawa
December 13, 2016
Programming
9.7k
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.4k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
590
Other Decks in Programming
See All in Programming
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
180
海上で動くGoサーバー: goroutineとchannelでさばく航行データストリーム
atsuki_seo
0
990
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
4
390
App Intentsのビルドプロセスを支える技術
kntkymt
0
470
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
160
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
720
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
420
mrbgem 三角測量 開発
ogom
0
120
wkhtmltopdfの次どうするか問題2026
willnet
2
1.8k
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
220
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
550
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
130
Featured
See All Featured
Git: the NoSQL Database
bkeepers
PRO
432
67k
Between Models and Reality
mayunak
4
470
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
GraphQLとの向き合い方2022年版
quramy
50
15k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
270
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
530
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
The Language of Interfaces
destraynor
162
27k
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!