2012-06-24 39 views
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) 

什麼是編寫這條產業鏈在斯卡拉驗證的最佳方式編寫以下邏輯是什麼?

回答

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) 

然後你可以通過它的右投影

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) 

使用的一元Either組合物,其中:

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的左側將出現錯誤消息。這個monadic組成是快速失敗。您可以使用scalazValidation累積所有故障(例如,如果既不存在XDir也不存在YDir,您將看到這兩個消息)的構圖。在這種情況下,代碼應該是這樣的:

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 
+0

我可以在沒有'scalaz'的情況下編碼錯誤累積嗎? – Michael

+0

好吧,如果你通過自己的圖書館引入相同的概念,你可以。你正在尋找的是**應用函子**和** monoids **的組合。但是,這些非常有用和普遍,你可能只是使用scalaz。 –

+0

我在這裏談論它們:http://skillsmatter.com/podcast/scala/practical-scalaz-2518 –

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(_)) 

凡安全執行,你猜對了,安全的(try/catch語句)的操作,需要一個失敗(左結果)消息,並返回一個非此即彼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) 

可以添加一個選項的方法來捕獲類爲好,用日誌記錄。

請參閱Jason Zaugg的關於right biasing Eitherthis thread的解決方案。目前還沒有達成共識,但大多數斯卡拉「重量級」似乎都贊成。

此方法的一個限制是,如果您嘗試向for {}塊添加條件(如果a = b),它將不會編譯(因爲默認的任一過濾器方法返回Option)。解決方法是實施過濾和withFilter,返回要麼,這是我還沒有搞清楚/ DO(如果有人已經這樣做了,請張貼)

+1

也見[確認](HTTPS:/ /github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Validation.scala)來自scalaz。 – mergeconflict

+0

@mergeconflict謝謝,還沒有潛入Scalaz,我的腳仍然在斯卡拉本身。 – virtualeyes