Created
March 17, 2015 07:14
-
-
Save nenono/b53dd7ce41629071a2fa to your computer and use it in GitHub Desktop.
Scalaのかんたんなモナド
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// もなもなしたアレ関係 | |
package object Monads { | |
// Option関係 | |
def optionTest = { | |
println("--optionTest--") | |
// Option(Maybe)型は標準搭載 | |
val o1 = Some("string!!") | |
val o2 = None | |
// パターンマッチ | |
List(o1, o2).foreach(_ match { | |
case Some(str) => println(s"some: ${str}") | |
case None => println("none!") | |
}) | |
// getOrElse | |
val o1_ = o1.getOrElse("defaultString") | |
val o2_ = o2.getOrElse("defaultString") | |
println(s"result:${o1_} ${o2_}") | |
// 合成 何れか一つの束縛が失敗した場合は何もしないで終了します | |
for { | |
x <- o1 | |
y <- Some(42) | |
} println(s"result:${x} ${y}") | |
// for式はHaskellのdo記法、C#のクエリ構文のように使えます。 | |
// 合成結果の値も使えます (実際はSome(x)の部分が何かの関数呼び出しの結果だと思ってください) | |
val result = for { | |
x <- Some(1) | |
y <- Some(2) | |
z <- Some(3) | |
} yield (x, y, z) | |
// result変数はSome((1, 2, 3))になっています | |
// getでの取り出しは、Noneの場合にエラーになるので非推奨です | |
println(result.get) | |
// C#で言うSelect/SelectManyを直接書くならmap, flatMapを使います | |
val result2 = | |
Some(1).flatMap(x => | |
Some(2).flatMap(y => | |
Some(3).map(z => | |
(x, y, z)))) | |
println(result2.get) | |
} | |
// List | |
def listTest = { | |
println("--listTest--") | |
// Listも当然monadなのでfor記法が使えます (そもそもList内包記法なんだから、と言う意見は無視します)。 | |
// とはいってもn重ループのようなパターンでは素直に使っていきます。 | |
val result = for { | |
x <- (1 to 5) | |
y <- (1 to 3) | |
} yield (x, y) | |
println(result) | |
// flatMapで書き下すとたぶんこうなるはずです | |
val result2 = | |
(1 to 5).flatMap(x => | |
(1 to 3).map(y => | |
(x, y))) | |
println(result2) | |
// 結果はどちらも以下です | |
// Vector((1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3), (4,1), (4,2), (4,3), (5,1), (5,2), (5,3)) | |
} | |
// Either | |
def eitherTest = { | |
println("--eitherTest--") | |
// 失敗時の値も保持できるOptionのようなものです | |
// 参考: http://yuroyoro.hatenablog.com/entry/20100719/1279519961 | |
val success = Right(42) | |
val error = Left("some error occurred!") | |
// パターンマッチ | |
List(success, error).foreach(_ match { | |
case Right(x) => println(s"success! value:${x}") | |
case Left(y) => println(s"failure! value:${y}") | |
}) | |
// この辺り結構型推論頑張ってくれてるっぽい感じがしますね | |
// for式も使えます (実際はRight(x)/Left(x)の部分が何かの関数呼び出しの結果だと思ってください) | |
val result = for { | |
a <- Right(1).right | |
b <- Right(2).right | |
c <- Left("some error occurred!").right | |
d <- Right(3).right | |
} yield (a, b, c, d) | |
println(s"result:${result}") // Left("some error occurred!") になります | |
// flatMapはEither[A, B]のright/leftに定義されていて、 | |
// right/leftで指定した方を「成功」とみなして次のステップに進むようになっているようです | |
// ちょっと面倒くさいところですね | |
// ガチで使うならscalazのEitherやValidationを使うほうが良いみたいです…… | |
// 機械的にflatMapで書き下すとこんな感じです | |
val result2 = | |
Right(1).right.flatMap(a => | |
Right(2).right.flatMap(b => | |
Left("some error occurred!").right.flatMap(c => | |
Right(3).right.map(d => | |
(a, b, c, d))))) | |
println(s"result:${result2}") | |
} | |
def main(args: Array[String]) { | |
optionTest | |
listTest | |
eitherTest | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment