Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ラムダ式禁止おじさん ver1.1 #Kotlin_Sansan

Taro Nagasawa
December 13, 2016

ラムダ式禁止おじさん ver1.1 #Kotlin_Sansan

第4回Kotlin勉強会 @ Sansan ( https://connpass.com/event/44710/ )で発表したスライドです。

Taro Nagasawa

December 13, 2016
Tweet

More Decks by Taro Nagasawa

Other Decks in Programming

Transcript

  1. 自己紹介 • 長澤 太郎 たろーって呼んでね ◦ @ngsw_taro • エンジニア@エムスリー株式会社 ◦

    ITで医療を変革! ◦ Android, Kotlin, Java, Spring, Railsなど • Kotlinエバンジェリスト • ディズニーが好き
  2. 関数参照 val println: (Int) -> Unit = ::println 123.let(println) 123.let(::println)

    関数オブジェクトへの 参照を取得できる
  3. 引数を2つ取る関数 fun minus(a: Int, b: Int) = a - b

    3.let { minus(5, it) } //=> 2 ここのラムダ式をなくしたい!
  4. デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:

    A): (B) -> R = { this(a, it) } 「AとBを引数に取り、Rを返す関数」に 拡張関数invokeを生やす
  5. デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:

    A): (B) -> R = { this(a, it) } Aを引数に取り、 「Bを引数に取り、Rを返す関数」を返す
  6. デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:

    A): (B) -> R = { this(a, it) } 演算子オーバロードにより function2.invoke(foo) ↓ function2(foo)
  7. デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:

    A): (B) -> R = { this(a, it) } つまり、invoke関数の存在によって (A, B)->R を (A)->((B)->R) とも見なせる
  8. デフォルトでカリー化してるっぽく見せる operator fun <A, B, R> ((A, B) -> R).invoke(a:

    A): (B) -> R = { this(a, it) } ※invokeはカリー化する関数ではありません。 ((A, B)->R)が1引数関数に見えるようにするための関数です。 あくまで「カリー化してるっぽく」見せているだけです。
  9. 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
  10. 関数の部分適用 5.let { minus(it, 3) } //=> 2 5.let((::minus)(3)) //=>

    -2 5.let((::minus)(_, 3)) //=> 2 プレースホルダーを置いて、 引数の位置をコントロールしたい!
  11. プレースホルダーを取る拡張関数invoke operator fun <A, B, R> ((A, B) -> R).invoke(p:

    PlaceHolder, b: B): (A) -> R = { this(it, b) } 「AとBを引数に取り、Rを返す関数」に 拡張関数invokeを生やす
  12. プレースホルダーを取る拡張関数invoke operator fun <A, B, R> ((A, B) -> R).invoke(p:

    PlaceHolder, b: B): (A) -> R = { this(it, b) } プレースホルダーとBを引数に取り、 「Aを取ってRを返す関数」を返す
  13. レシーバが指定されたメソッド参照 // 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); }
  14. レシーバが指定されたメソッド参照 // 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メソッド
  15. 一方、Kotlinは... class Calculator { fun succ(x: Int): Int = x

    + 1 } val calc = Calculator() 2.let(calc::succ) // NG 2.let { calc.succ(it) } // こう書くしか…?
  16. 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
  17. 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
  18. つまり val calc = Calculator() 2.let(calc::succ) // NG 2.let {

    calc.succ(it) } // OK 2.let { (Calculator::succ)(calc, it) } // OK
  19. さらに 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
  20. さらに 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 を省略して、ラムダ式を消せる!
  21. ちょっと待った!! class Calculator { fun succ(x: Int): Int = x

    + 1 } val calc = Calculator() 2.let(calc::succ) // NG 2.let { calc.succ(it) } // こう書くしか…?
  22. ちょっと待った!! class Calculator { fun succ(x: Int): Int = x

    + 1 } val calc = Calculator() 2.let(calc::succ) // OK ver1.1から 2.let { calc.succ(it) } // こう書くしか…? ラムダ式禁止が捗るね!!
  23. 関数のnullable対応 fun <A, R> ((A) -> R).nullOk(): (A?) -> R?

    = { it?.let(this@nullOk) } 普通の関数を取って
  24. 関数のnullable対応 fun <A, R> ((A) -> R).nullOk(): (A?) -> R?

    = { it?.let(this@nullOk) } 「nullableを取って、 nullableを返す関数」を返す