使用\ /和IO的For-Understarehension示例

时间:2015-06-19 01:24:21

标签: scala scalaz

给出以下Foo案例类:

scala> case class Foo(x: Int)
defined class Foo

我在Foo内构建它之前检查它是否有效validateFoo

scala> def validateFoo(foo: Foo): \/[String, Foo] = 
              (if(foo.x > 0) foo.success[String] 
              else ("invalid foo").failure[Foo]).disjunction
validateFoo: (foo: Foo)scalaz.\/[String,Foo]

最后,f创建Foo,然后尝试执行IO操作(例如:将Foo保存到数据库中)。

scala> def f(x: Foo): IO[\/[String,Int]] = for {
     |    foo <- validateFoo(x)
     |    ioFoo <- IO { foo }
     | } yield ioFoo
<console>:19: error: type mismatch;
 found   : scalaz.effect.IO[Foo]
 required: scalaz.\/[?,?]
          ioFoo <- IO { foo }
                ^
<console>:18: error: type mismatch;
 found   : scalaz.\/[String,Nothing]
 required: scalaz.effect.IO[scalaz.\/[String,Int]]
          foo <- validateFoo(x)
              ^

然而,当我试图在for-comprehension中将bind链接在一起时,我遇到了上述问题。

正如我所看到的,问题是正确的返回类型是IO[\/[String, Int]]。但是,我不知道如何验证Foo IO monad中处理它是否具有for-comprehension。

2 个答案:

答案 0 :(得分:5)

你不能将这样的String \/ AIO[A]计算结合起来 - 如果你贬低了你的for - 理解,你就会发现这些类型无法解决。

如果你真的想,你可以使用monad变换器来组成两个monad。假设我们有以下设置(例如,它本质上是您的代码,但清理了一下,并使用表示数据库操作的新方法):

import scalaz._, Scalaz._, effect._

case class Foo(x: Int)

def validateFoo(foo: Foo): String \/ Foo =
  (foo.x > 0) either foo or "invalid foo"

def processFoo(foo: Foo): IO[Foo] = IO {
  println(foo)
  foo
}

现在我们可以写下以下内容:

type IOStringOr[A] = EitherT[IO, String, A]

def f(x: Foo): IOStringOr[Foo] = for {
  foo <- EitherT(validateFoo(x).point[IO])
  ioFoo <- processFoo(foo).liftIO[IOStringOr]
} yield ioFoo

现在,您可以运行EitherT来获取IO操作:

val ioAction: IO[String \/ Foo] = f(Foo(10)).run

这就是 \/ - 理解中}和IO一起使用的方式。不过,这对你的情况来说肯定是过分杀戮。我可能会写这样的东西:

for

这使用def f(x: Foo): IO[String \/ Foo] = validateFoo(x).bitraverse(_.point[IO], processFoo) 的{​​{1}}实例将函数映射到析取两边的Bitraverse,然后将整个内容转换为内部。

答案 1 :(得分:-2)

您的validateFoo定义中似乎有错误。我想你想要

scala> def validateFoo(foo: Foo): \/[String, Foo] = 
          (if(foo.x > 0) foo.success[Foo] 
          else ("invalid foo").failure[String]).disjunction

你在成功和失败案件中混淆了String和Foo。