在scalaz` \ /`中转换`Option [Tuple]`

时间:2014-12-12 12:23:35

标签: scala scalaz

我正在尝试从Option[Tuple]创建连接,然后返回 结果是分离,但我的代码看起来有点奇怪:

  def ssh(config: GushConfig): \/[Throwable, Client] = {
    val params = for {
      host <- config.mysqlHost
      port <- config.mysqlPort
      user <- config.mysqlUser
      password <- config.mysqlPassword
      sshAddress <- config.sshTunnelAddress
      sshTunnelUser <- config.sshTunnelUser
    } yield (host, port, user, password, sshAddress, sshTunnelUser)

    params match {
      case Some((host, port, user, password, sshAddress, sshTunnelUser)) ⇒
        Try({
          // Do stuff that can fail and throw exceptions

          new Client("127.0.0.1", lport, user, password)
        }) match {
          case Success(v) ⇒ v.right
          case Failure(t) ⇒ t.left
        }
      case None ⇒
        new Exception("Not enough parameters to initialize a ssh client").left
    }
  }

我首先需要模仿匹配我的第一个Option以检查我有 所有必需的选项,然后如果我这样做,尝试在Try内连接 然后将try的结果转换为析取。

有没有更好的方法来进行这种转变?

2 个答案:

答案 0 :(得分:6)

您可能希望将它们转换为相同的类型 - 您可以在.toRightDisjunction上使用Option,而您可以使用Try执行scala.util.control.Exception事件:

import scala.util.control.Exception._

for {
  params_ ← params.toRightDisjunction(
    new Exception("Not enough parameters to initialize a ssh client"))
  (host, port, user, password, sshAddress, sshTunnelUser) = params_
  v ← catching(classOf[Exception]) either functionThatCouldThrow() disjunction
} yield v

您还可以使用Option而不是明确的.sequence / for执行初始yield事件(这可能需要shapeless-scalaz):

params = (config.mysqlHost, config.mysqlPort, ...).sequence

答案 1 :(得分:3)

scalaz.std包中包含

object option extends OptionInstances with OptionFunctions {
  object optionSyntax extends scalaz.syntax.std.ToOptionOps with scalaz.syntax.std.ToOptionIdOps
}

Scalaz添加到scala.Option的操作在OptionInstances(类型类)和OptionsFunctions中定义。 OptionFunctions包含以下方法:

  final def toRight[A, E](oa: Option[A])(e: => E): E \/ A = oa match {
    case Some(a) => \/-(a)
    case None    => -\/(e)
  }

  final def toLeft[A, B](oa: Option[A])(b: => B): A \/ B = oa match {
    case Some(a) => -\/(a)
    case None    => \/-(b)
  }

语法和隐式转换在scalaz.syntax包中提供,特别是OptionOps是Scalaz“Rich Option”。 ToOptionOps包含Option => OptionOps

的隐式转化

如果正确导入optionSyntax,则可以编写以下内容

import scalaz.std.option.optionSyntax._
val disjunction = params.\/>(new Exception("Not enough parameters to initialize a ssh client"))

然后你可以从那里映射/ flatMap