2014-06-20
■ [haskell][scala] ScalaのEitherとHaskellのEitherはちょっと違うらしい
このへん見てたら、ScalaのEitherはHaskellのとちょっと違って、より柔軟なことができる(代わりに記述が少しだけ増える)らしいという話があって面白かった。 (※自分用のメモなので分かりにくいかもしれないです。)
お題
def index(id:String) = Action {
Cache.get(id) match {
case Some(id2) => {
Cache.get(id2) match {
case Some(result) => Ok(result)
case None => NotFound
}
}
case None => NotFound
}
}
これをどうやって綺麗に書くか、という話。
でHaskellならEither aがモナドだからEitherとdoでこう書けるんだけどという話が出た、
getCache :: String -> Maybe String
nanika id = do
id2 <- getCacheOr id NotFound
id3 <- getCacheOr id2 BadRequest
result <- getCacheOr id3 NotFound
return result
where
getCacheOr id nothing = fromMaybe (Left nothing) $ Right <$> getCache id
で、ScalaのEitherではできないのかというと、実は.rightというメソッドがあるんですね。
RightProjection
HaskellのEitherは「Leftはエラー情報を持ち、Rightは成功時のデータを持つ」という使い方を想定してるので、do記法を使った場合は「Rightなら計算を続け、Leftならそこで中止する」という定義になっている。 一方ScalaのEitherは、LeftもRightも等価なものとして扱えるようになっているみたい。そのため生のEitherはforに使えない。
その代わりRightProjection, LeftProjectionをとるとforで使えるようになる。
a :: Either[String, Int]
という変数があったとき、a.right
とすると何が返ってくるか。最初はOption[Int]が返るのかな?と思ったのだけど、RightProjectionのインスタンスが返るらしい。これはもとのEitherをラップしたものだけど、flatMapが定義してあって、「Rightなら計算を続け、Leftならそこで中止する」という定義になっている。で、同様にa.left
とやるとLeftProjectionが返って、こっちのflatMapは「Leftなら計算を続け、Rightならそこで中止する」という定義になっていると。
ちなみに
scalazではEither自体もflatMapできるらしい。 http://togetter.com/li/287993?page=5 http://d.hatena.ne.jp/cooldaemon/20111017/1318862426