6

Scala で次のロジックをコーディングしたいとします。

val xdir = System.getProperty("XDir")
もし (xdir == null)
   error("No XDir") // エラーをログに記録して終了します

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

if (!new File(xdir).isDirectory)
   error("XDir はディレクトリではありません")

if (!new File(ydir).isDirectory)
   error("YDir はディレクトリではありません")

if (!new File(xdir).exists)
   error("XDir が存在しません")

if (!new File(ydir).exists)
   error("YDir が存在しません")
...
(等々)

この一連の検証を Scala でコーディングする最良の方法は何ですか?

4

3 に答える 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を通じてのモナド構成を使用できます

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はエラー メッセージです。このモナド合成はフェイルファストです。scalazを使用して、すべての失敗を蓄積する構成を実現できます (たとえば、どちらXDirYDir存在しない場合、両方のメッセージが表示されます) 。その場合、コードは次のようになります。 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
于 2012-06-24T22:38:19.433 に答える
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 は、ご想像のとおり、失敗 (左の結果) メッセージを受け取り、Either RightProjection を返す安全な (try/catch) 操作を実行します (これにより、障害点エラー メッセージをスレッド化しながら上記のバッチ操作を実行できます)。 )

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 クラスに追加することもできます。また、特定のエラー タイプをログに記録する場合は、ログを記録することもできます。

Jason Zaugg's solution for right biasing eitherと、件名に関する scala-debate のこのスレッドも参照してください。まだコンセンサスはありませんが、ほとんどの scala の「ヘビー」が支持されているようです。

このアプローチの 1 つの制限は、条件 (a = b の場合) を for{} ブロックに追加しようとすると、コンパイルされないことです (デフォルトのいずれかのフィルター メソッドが Option を返すため)。回避策は、filter と withFilter を実装し、Either を返すことです。まだ解決していない/実行していないことです (誰かが既に実行している場合は、投稿してください)。

于 2012-06-24T15:57:33.670 に答える