将Either作为fs.Stream处理

时间:2018-04-20 16:05:55

标签: scala scalaz scala-cats fs2

如果我有fs2.StreamApp[IO],那么在构建主应用流时,如何最好地处理Either(或\/)?

例如,我为程序建立了一些输入(因为我喜欢API - 它告诉我"某些内容可能出错"在签名中)。如果有问题,在这种情况下使用命令行参数,我想要从main方法返回一个不同的流。

private def extractArgs(args: List[String]): Error \/ List[_] = args match {
  case Nil  => CommandLineError().left
  case args => args.map(/* whatever */).right
}

当我进入主要方法时......

def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] = {

  val application: Error \/ Stream[IO, ExitCode] = for {
    args   <- extractArgs(args)
    x      <- someOtherEither
  } yield Stream.eval(...)

  application match {
    case -\/(error) => Stream.eval(IO(Log.error(error.message))).flatMap(_ => Stream.emit(ExitCode(1)))
    case \/-(ok)    => ok
  }
}

......一切都变得有点难看。

我可以让析取方法(extractArgs)只返回错误情况的流,但这似乎很有意思。特别是因为我不知道如何快速失败。

是否有更惯用的方式将左侧变为错误流(在我的情况下打印使用命令然后退出应用程序)?

1 个答案:

答案 0 :(得分:0)

我认为来自猫.valueOr的{​​{1}}将是一个不错的选择,并且可以考虑更小的功能。

这将产生如下内容:

EitherOps

object Logger { def error(msg: String): IO[Unit] = IO(Log.error(msg)) } def runWithArgs(args: List[String]: Error \/ Stream[IO, ExitCode] = for { args <- extractArgs(args) x <- someOtherEither } yield Stream.eval(...) def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] = runWithArgs(args) valueOr { error => Stream.eval(Logger.error(error.message)) .map(_ => ExitCode(1)) } 的签名是:

.valueOr

您将def valueOr[BB >: B](f: A => BB): BB A设为B