Scalaでdef hoge = { case _ => fuga() }がパターンマッチのように見えるけどどうなってるのかわからなかったので調べたら部分関数(PartialFunction)について学びがあった話

結論を先に書くと、{ case _ => fuga() } の型はFunction1のサブトレイトのPartialFunctionだった。

Scalaやりはじめてとにかく思ったのが

コードが読めない

“シンプルで柔軟性のある基本文法” に対して、それを読み書きしやすくするシンタックスシュガーがScalaでは大量に定義されていて、いかんせん読むのに苦労する。慣れなんだろうけど。

今回はAkkaの勉強をしてみたら、早速以下の様な記法が出てきて頭を抱えた。

import akka.actor.Actor

class HelloActor extends Actor{
  def receive = {
    case "Hello" => println("World")
  }
}

これをどう読んだらいいかはなんとなくわかる。書いてあるとおりだ。
きっとreceiveが{ }ブロックを返して、{ }ブロックはなにか受け取ってcaseでパターンマッチして処理を実行する。返る型はUnit。

なのだが、このシンタックスはよくわからない。receiveはdefされているのでメソッドのはずだけど、これだけだと戻り値{ case _ => fuga() }の型がわからない。

とりあえずREPLで試す

なのでとりあえずREPLで書いて型を見てみることにした。

scala>   def receive = {
     |     case "Hello" => println("World")
     |   }
<console>:7: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
         def receive = {
                       ^

予想通りの結果で、戻り値の型(となる関数?の引数の型)が特定できないのでエラーになる。
さらに、{ case _ => fuga() }は引数を1つとるUnit型の関数だと考えられるので、型を与えてみる。

scala> def receive: String => Unit = {
     | case "Hello" => println("World")
     | }
receive: String => Unit

というわけで、{ case _ => fuga() }の型がFunction1[A, B]っぽいことがわかった。

Akka.actor.Actor の定義を見る

最初からこっちをやればよかったのだが、答え合わせとしてやった。

receiveの定義は

trait Actor {
  …
  def receive: Actor.Recieve
  …
}

ここでActor.Recieveは

object Actor {
  …
  type Receive = PartialFunction[Any, Unit]
  …
}

予想に反してFunction1[A,B]型ではなかったが、PartialFunction[A, B]はFunction1[A, B]のサブトレイトだったので、納得。

PartialFunctionとは

せっかくなのでPartialFunctionについても調べてみた。基本はFunction1と同じように考えて良い(雑)
ざっくり言うと、関数の入力定義域が限られていて、定義外の入力については出力を保証しない関数のことを部分関数・PartialFunctionと呼ぶようだ。

詳しくはゆるよろ先生のScalaのPartialFunctionが便利ですよがわかりやすかった。

参考:【Akka入門の入門】Part.1 メッセージを送る

広告

Scalaでdef hoge = { case _ => fuga() }がパターンマッチのように見えるけどどうなってるのかわからなかったので調べたら部分関数(PartialFunction)について学びがあった話」への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中