entry-header-eye-catch.html
entry-title-container.html

entry-header-author-info.html
Article by

【Scala】任意の値からメソッドチェーンを生やすメソッドを車輪の再発明した話

はじめに

はじめましての方ははじめまして。 Scala エンジニアの Javakky です!

今回は、 Scala の標準ライブラリにある pipe / tap というメソッドを求めて旅した過程を書いていこうと思います。

pipe / tap とは?

Scala Standard Library 2.13.6 - scala.util.ChainingOpsで定義されているメソッドで、任意の値をメソッドチェーンのソースとして扱えるすごいやつです。

pipe

pipe メソッドは任意の値を受け取り、処理結果を返す関数に値を渡してくれるメソッドです。

今回求めていた機能もこいつになります。

/** Converts the value by applying the function f. */
def pipe[B](f: (A) => B): B

// example
val i = (1 - 2 - 3)
  .pipe((_: Int) * 6)
  .pipe(scala.math.abs)
// i: Int = 24

tap

また、同じクラスで定義されている tap メソッドでは、元の値に任意の処理をしつつ、値をそのまま返すことができます。

戻り値のない処理をメソッドチェーンの中間でやりたくなった時に便利です。

/** Applies f to the value for its side effects, and returns the original value. */
def tap[U](f: (A) => U): A

// example
val xs = List(1, 2, 3)
  .tap(ys => println("debug " + ys.toString))
// debug List(1, 2, 3)
// xs: List[Int] = List(1, 2, 3)

発端

イミュータブルな処理を手続き的に書く際に、1処理ごとに変数の命名を行うのは面倒くさいな〜でも時々は前処理の結果を複数回使いたいな〜と考えていました。

やりたい処理はこんな感じ ↓

var target = init()
target = target.hoge()
target = target.huga()
target = target.piyo()
target

これは、メソッドチェーンで以下のように書くことができます。

init().hoge().huga().piyo()

しかし、以下のようなコードではどうでしょうか?

var target = init()
target = target.hoge()
target = target.huga() match {
  case A => A
  case _ => target
}
target = target.piyo()
target

一応 match を利用して変数を再定義してやれば書くことができました。

var target = init()
target.hoge() match {
  case target => target.huga() match {
    case A => A
    case _ => target
  } match {
    case target => target.piyo()
  }
}

しかし、これだと手続きの行数が増えれば増えるほど、ネストがどんどん深くなってしまいます。

Implicit Conversion で自作しよう

ここで任意の型 A をメソッドチェーンに変換することができればやりたいことができるのでは?と思いつきました。

implicit class UsePrevious[A](a: A) {
  def use[B](f: A => B): B = f(a)
}

これがあれば以下のように書くことができるので、1段分のネストは生まれてしまうものの、全ての処理を縦に並べて記述することができました。

init()
  .hoge()
  .use { target =>
    target.huga() match {
      case A => A
      case _ => target
    }
  }.piyo()

終幕

はい。無事全く同じシグネチャのメソッドが Scala の標準ライブラリにありました。

リプライをくださった皆さん、ありがとうございました。

みなさんもぜひ色々な標準ライブラリを触ってみてください。

icon
javakky
決済周りの改善を中心に働いている2021年入社エンジニア。その名の通りJavaが好きなことで有名(?)で、最近はScalaを使える部署へ入ったらしい。