Вопрос по scala – Как кодировать эту логику проверки в Scala?

6

Предположим, я хотел бы написать следующую логику в Scala

val xdir = System.getProperty("XDir")
if (xdir == null)
   error("No XDir") // log the error and exit

val ydir = System.getProperty("YDir") 
if (ydir == null)
   error("No YDir")

if (!new File(xdir).isDirectory)
   error("XDir is not a directory")

if (!new File(ydir).isDirectory)
   error("YDir is not a directory")

if (!new File(xdir).exists)
   error("XDir does not exis")

if (!new File(ydir).exists)
   error("YDir does not exist")
...
(and so on)

Каков наилучший способ кодирования этой цепочки проверок в Scala?

Ваш Ответ

3   ответа
4

def sysValue(prop: String) = Option(System.getProperty(prop)) //returns Option[String]

def trySysValue(prop: String) = //returns Either[String, String]
  sysValue(prop) map Right getOrElse Left("Absent property: " + prop)

Тогда вы можете использовать монадную композициюEither через егоright-projection

val batch = //batch is Either[String, (File, File)]
  for {
    x  <- trySysValue("XDir")).right
    xf <- dir(x).right
    y  <- trySysValue("YDir").right
    yf <- dir(y).right
  } 
  yield (xf, yf)

Куда:

def dir(s: String) = { //returns Either[String, File]
  val f = new File(s)
  if (!f.exists()) Left("Does not exist: " + f)
  else if (!f.isDir()) Left("Is not a directory: " + f)
  else Right(f)
}

Левая сторонаEither будет сообщение об ошибке. Эта монадическая композицияfail fast, Вы можете достичь композиции, которая будет накапливать все неудачи (например, если ни один изXDir ниYDir существует, вы увидите оба сообщения) используяscalaz Validation, В этом случае код будет выглядеть так:

def trySysValue(prop: String) = //returns Validation[String, String]
  sysValue(prop) map Success getOrElse ("Absent property: " + prop).fail

def dir(s: String) = {
  val f = new File(s)
  if (!f.exists())("Does not exist: " + f).fail
  else if (!f.isDir()) ("Is not a directory: " + f).fail
  else f.success
}

val batch = //batch is ValidationNEL[String, (File, File)]
  (trySysValue("XDir")) flatMap dir).liftFailNel <|*|> (trySysValue("YDir")) flatMap dir).liftFailNel
Я говорю о них здесь:skillsmatter.com/podcast/scala/practical-scalaz-2518
Ну, вы могли бы, если бы вы вводили те же понятия через свою собственную библиотеку. То, что вы ищете, является комбинациейapplicative functors а такжеmonoids, Тем не менее, они настолько полезны и распространены, что вы можете просто использовать скалаз.
Можно ли кодировать накопление ошибок безscalaz ? Michael
4

val batch = for{
  a <- safe(doA, "A failed") either
  b <- safe(doB, "B failed") either
  c <- safe(doC, "C failed") either
} yield(a,b,c)
batch fold( error(_), doSuccess(_) )

Где safe выполняет, как вы уже догадались, безопасную (try / catch) операцию, которая принимает сообщение об ошибке (Left output) и возвращает Either RightProjection (которое позволяет вам выполнить вышеупомянутую пакетную операцию при прохождении через сообщение об ошибке точки отказа) )

class Catching[T](f: => T) {
  def either(msg: String) = {
    try { Right(f).right } catch { Left(msg).right }
  }
}
def safe[T](f: => T) = new Catching(f)

Можно также добавить метод метода в класс Catching вместе с ведением журнала, если вы хотите регистрировать определенные типы ошибок.

См. Решение Джейсона Заугга длясмещение вправо либо а такжеэта тема от scala-дебатов на эту тему. Пока нет единого мнения, но большинство scala "тяжеловесов" кажется, в пользу.

Одним из ограничений этого подхода является то, что если вы попытаетесь добавить условные выражения (если a = b) в блок for {}, он не будет компилироваться (поскольку метод фильтра Either по умолчанию возвращает Option). Обходной путь должен реализовать filter и withFilter, возвращая Either, то, что я еще должен выяснить / сделать (если кто-то уже сделал это, пожалуйста, напишите)

@mergeconflict спасибо, мне еще предстоит погрузиться в Скалаз, все еще мокрые в самой Скале.
смотрите такжеValidation от скалаза.
1

вы можете использовать проверку без скаляза, смотрите здесь для самостоятельной реализации: http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/chunk-xhtml/apa.html НТН

Похожие вопросы