Я пытаюсь установить соединение с 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 а затем преобразовать результат попытки в дизъюнкцию.

Есть ли лучший способ сделать это преобразование?

4
simao 12 Дек 2014 в 15:23

2 ответа

Лучший ответ

Возможно, вы захотите преобразовать их обоих в один и тот же тип - вы можете использовать .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
6
lmm 12 Дек 2014 в 16:55

Пакет 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 оттуда

3
Edmondo 12 Дек 2014 в 17:09