異なるタイプのネストされたモナドは、モナドが同じタイプであることを理解するために、扱いにくいことがあります。あなたは行うことができます次のいずれかの
val mappedValue = for (fut <- deepMonad) yield {
for (opt <- fut) yield {
for (bool <- opt) yield {
//some logic
}
}
}
またはあなたがあなたのためにそれを離れて隠しutilのを作ることができるためにネストされたの
たくさん。
プロジェクトで一般的に使用する特定の構造を見ていて、純粋なScalaを使いたい場合は、以下のようにマップ/ foreachを行うことができます。
など。
object MyUtils {
implicit class MyWrapper[A](deepMonad: Option[Future[Option[A]]]) {
def fmap[B](f: A => B) = {
for (fut: Future[Option[A]] <- deepMonad) yield {
for (opt: Option[A] <- fut) yield {
for (b: A <- opt) yield {
f(b)
}
}
}
}
def myForeach[U](f: A => U): Unit = {
for (future <- deepMonad) {
for (opt <- future) {
for (b <- opt) {
f(b)
}
}
}
}
}
}
object Test extends App {
import MyUtils._
val deepMonadExample:Option[Future[Option[Boolean]]] = Some(Future.successful(Some(true)))
val x: Option[Future[Option[String]]] = deepMonadExample.fmap {
case v:Boolean => "Result: "+v
}
x.myForeach{ v => println(v) }
}
Scalazを使用したい場合は、Monadクラスを使用してより汎用的なユーティリティを作成できます。 Scalazには、オプション、未来、そして他のものを箱の中で動かすような、あらかじめ組み込まれた意味があります。しかし、JsResultのようなクラスにはscalaz Monadのインスタンスがないので、それを作る必要があります。
など。
import play.api.libs.json.{JsSuccess, JsError, JsResult}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scalaz.Monad
//this creates the fmap method
object HandleDeepMonads {
import scala.language.higherKinds
import scalaz.Monad
import scalaz.Scalaz._
implicit class ThreeMonadMap[M[_] : Monad, M2[_] : Monad, M3[_] : Monad, A](v: M[M2[M3[A]]]) {
def fmap[B](f: A => B): M[M2[M3[B]]] = {
for (a <- v) yield
for (b <- a) yield
for (c <- b) yield f(c)
}
}
}
//Since JsResult has no native Monad in scalaz - you can make your own one
object MyCustomMonads {
implicit object JsResultMonad extends Monad[JsResult] {
def point[A](a: => A): JsResult[A] = JsSuccess(a)
def bind[A, B](fa: JsResult[A])(f: A => JsResult[B]): JsResult[B] = fa match {
case JsSuccess(v, _) => f(v)
case [email protected](_) => e
}
}
}
object Test extends App {
import HandleDeepMonads._
import MyCustomMonads._
import scala.language.higherKinds
import scalaz.Scalaz._
val deepMonadExample: Option[Future[JsResult[String]]] = Some(Future.successful(JsSuccess("Hello")))
val deepMonadExample2: Option[Future[JsResult[Boolean]]] = Some(Future.successful(JsError(Nil)))
val deepMonadExample3: Option[Future[Option[Boolean]]] = Some(Future.successful(Some(true)))
val deepMonadExample4: Option[Future[JsResult[Boolean]]] = None
// Some(successful(JsSuccess("Result: true")))
val x = deepMonadExample.fmap {
"Result: " + _
}
// Some(successful(JsError()))
val x3 = deepMonadExample3.fmap {
"Result: " + _
}
// Some(successful(Some("Result: Hello")))
val x2 = deepMonadExample2.fmap {
"Result: " + _
}
// None
val x4 = deepMonadExample4.fmap {
"Result: " + _
}
}
あなたが深い2に、あなたのモナドを簡素化することができれば、あなたが(コメントで示唆されているように、例えばOptionT)をScalazの株式標準モナド変圧器を使用することができます。私は彼らが2つの深さで非常によく働いているのを見ましたが、私はもっとネストした状態でそれらを使ったことはありません。
答えは、それぞれのレベルが何を意味しているのか、そしてこれらのことで何をするのかにある程度依存します。もっと知らないと、 'Future'と' JsResult'を単一の 'Future'レベルに平坦化し、' Future'の中で 'Option'を動かし、(CatsかScalazの依存関係ならば)その結果を 'OptionT [Future、LoginResponse]'に変換します。 –
a)http://eed3si9n.com/learning-scalaz/Monad+transformers.html b)http://atnos-org.github.io/eff-cats/ – Reactormonk
@Reactormonk Monadトランスフォーマーはアイデアかもしれません。ポスターが彼の例としてどのように使用できるかについてのサンプルコードがあります:Option [Future [JsResult [LoginResponse]]]これは素晴らしいものです。私は答えとして私の最善の努力をしました - しかし、それが良いものがあるかどうかを見ることは良いでしょう –