假设我想在Scala中编写以下逻辑
val xdir = System.getProperty(“XDir”)
如果(xdir == null)
error(“No XDir”)//记录错误并退出
val ydir = System.getProperty(“YDir”)
如果(ydir == null)
错误(“没有YDir”)
如果(!new File(xdir).isDirectory)
错误(“XDir不是目录”)
如果(!new File(ydir).isDirectory)
错误(“YDir不是目录”)
如果(!new File(xdir).exists)
错误(“XDir不存在”)
如果(!new File(ydir).exists)
错误(“YDir不存在”)
...
(等等)
在Scala中编写此验证链的最佳方法是什么?
最佳答案
这里有一些有用的东西:
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
的单子(monad)组合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
的左侧将是一条错误消息。这种单子(monad)组成很快就失败了。您可以使用 scalaz XDir
实现构图,该构图将累积所有失败(例如,如果YDir
和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