使用 for-yield 对 Scalaz WriterT 和两者进行排序 [英] Sequencing both Scalaz WriterT and Either with for-yield

查看:40
本文介绍了使用 for-yield 对 Scalaz WriterT 和两者进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有:

import scala.concurrent._
import scalaz._, Scalaz._

type Z = List[String]
type F[α] = Future[α]
type WT[α] = WriterT[F, Z, α]

implicit val z: Monoid[Z] = new Monoid[Z] {
  def zero = Nil
  def append (f1: Z, f2: => Z) = f1 ::: f2
}
implicit val f: Monad[F] = scalaz.std.scalaFuture.futureInstance

我可以这样写代码:

def fooA (): WT[Int] = WriterT.put[F, Z, Int] (f.point (18))(z.zero)
def fooB (): WT[Int] = WriterT.put[F, Z, Int] (f.point (42))(z.zero)
def fooLog (msg: String): WT[Unit] = WriterT.put[F, Z, Unit] (f.point (()))(msg :: Nil))

def foo (): WT[Int] = for {
  _: Unit <- fooLog ("log #1")
  a: Int  <- fooA
  _: Unit <- fooLog ("log #2")
  b: Int  <- fooB
  _: Unit <- fooLog ("log #3")
} yield a + b

假设我定义:

type WTT[α] = WriterT[Future, Z, Throwable \/ α]

def flakeyInt (i: Int): Throwable \/ Int = new java.util.Random().nextBoolean match {
  case false => i.right
  case true => new Exception (":-(").left
}

然后我可以这样写:

def barA (): WTT[Int] = WriterT.put[F, Z, Throwable \/ Int] (f.point (flakeyInt (18)))(z.zero)
def barB (): WTT[Int] = WriterT.put[F, Z, Throwable \/ Int] (f.point (flakeyInt (42)))(z.zero)
def barLog (msg: String): WTT[Unit] = WriterT.put[F, Z, Throwable \/ Unit] (f.point (().right))(msg :: Nil))

def bar (): WTT[Int] = for {
  _: Throwable \/ Unit <- barLog ("log #1")
  x: Throwable \/ Int  <- barA
  _: Throwable \/ Unit <- barLog ("log #2")
  y: Throwable \/ Int  <- barB
  _: Throwable \/ Unit <- barLog ("log #3")
} yield {
  for {
    a <- x
    b <- y
  } yield a + b
}

有没有办法在 for-yield 返回类型 α 中制作 <-,而不是 \/[Throwable, α] 所以我最后不必手动压平 Throwables?理想情况下,我想让 bar 函数看起来像 foo 函数,这样我就可以隐藏逻辑中的扁平化错误.

Is there a way to make the <- in the for-yield return type α, not \/[Throwable, α] so I don't have to manually flatten the Throwables at the end? Ideally I would like to make the bar function look like the foo function so that I can hide flattening the errors from the logic.

跟进问题:

在 Scalaz 中自定义 Future、Either 和 Writer 的组合

推荐答案

你应该将你的 Future monad 包装在 ThatiT 中,并随意修改你的代码.它看起来像这样:

you should wrap your Future monad in the EitherT, sightly modifying your code. It would look like that:

type EFT[α] = EitherT[F, Throwable, α]
type WEFT[α] = WriterT[EFT, Z, α]

def bazA(): WEFT[Int] = WriterT.put[EFT, Z, Int](EitherT.right[F, Throwable, Int](f.point(18)))(z.zero)

def bar(): WEFT[Int] = for {
  a <- bazA
  b <- bazA
} yield a + b

您还可以定义提升函数(将值从一个 monad 提升到您的转换器)以避免样板.

You can also define lift functions (which lifts the value from one monad to your transformer) to avoid boilerplate.

def liftW[A](fa: Future[A]): WLET[A] = {
    WriterT.put[MLT, Z, A](EitherT.right[Future, Throwable, A](fa))(z.zero)
 }

  def bbar(): WLET[Int] = for {
    a ← liftW(6.point[F])
    b ← liftW(6.point[F])
  } yield a + b

我确信在 scalaZ 中存在提升函数,但我总是很难找到它们,而且有时这些看起来更容易自己编写.

I am sure that lift functions are present in scalaZ, but I am always struggling to find them, and it appears that sometimes these are easier to write yourself.

这篇关于使用 for-yield 对 Scalaz WriterT 和两者进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆