Takuya71 のぶろぐ

外資系ソフトウェア会社で働いてます、認定スクラムマスター

Scalaz IdOps の |>

IdOps の |>

Scalaz では 以下のような構文を実行すると ある値を |> で右側の式に渡すようなことができます。

"hoge" |> (_.size)

何が起こっているかというと -Xprint:typer をつけてコンパイラの結果をみると 上記の式は

scalaz.this.Scalaz.ToIdOps[java.lang.String]("hoge").|>[Int](((x$1: java.lang.String) => scala.this.Predef.augmentString(x$1).size));

という式に変換されています。

String型の "hoge"が 型クラス IdOpsに暗黙的に変換されます。 このおかげで IdOps 型クラスに定義されている |> というメソッドが使用可能です。

ToIdOps は IdOps.scala で定義されております。

trait ToIdOps {
  implicit def ToIdOps[A](a: A): IdOps[A] = new IdOps[A] {
    def self: A = a
  }
}

|> は IdOps で定義されています。

def |>[B](f: (A) ⇒ B): B

型Aをとって型Bにする関数を引数にとる関数です。

その結果 上の例の場合だと String "hoge" をとって Int で hoge のサイズ 4 を返すことになります。

実験

scala> def adddesu(s:String):String = {
     |  s + "-desu"
     | }
adddesu: (s: String)String

こういう関数を定義し、これに |> つかって値を適用してみました。

scala> "hoge" |> adddesu
res0: String = hoge-desu

これは成功

scala> "hoge" |> adddesu()
<console>:15: error: not enough arguments for method adddesu: (s: String)String.
Unspecified value parameter s.
              "hoge" |> adddesu()
                               ^

これはエラーになりした。

scala> "hoge" |> adddesu(_)
<console>:15: error: missing parameter type for expanded function ( (x$1) => "hoge".$bar$greater(adddesu(x$1)))
              "hoge" |> adddesu(_)
                                ^
<console>:15: error: type mismatch;
 found   : String
 required: java.lang.String => ?
              "hoge" |> adddesu(_)
                               ^

これもエラー これらの記述がエラーになるのは 上のコンパイラの展開結果をみると、納得できる。

scala> "hoge" |> (adddesu(_))
res3: String = hoge-desu

scala> "hoge".|> (adddesu(_))
res4: String = hoge-desu

scala> "hoge".|> [String](adddesu(_))
res5: String = hoge-desu

これらは OK