8

たとえば、エラーがない場合はNoneを返す「検証」関数がたくさんあり、そうでない場合はエラーメッセージを指定するSome(String)を返します。次のようなもの...

def validate1:Option[String] 
def validate2:Option[String]
def validate3:Option[String]

それらを順番に呼び出し、Some(String)を返すとすぐに停止して、同じものを返します。Noneが返された場合は、シーケンスが終了するまで次へ進みます。それらすべてがNoneを返す場合、私はNoneを返します。

それらを「表現のために」接着したいと思います。何かのようなもの ...

for( a <- validate1; b <- validate2; c <- validate3) yield None;

ただし、Optionは、ここで必要なものとは正反対に流れます。Noneで停止し、Some(String)が続きます。

どうすればそのようなことを達成できますか?

4

4 に答える 4

17

オプションのorElseメソッドを使用して呼び出しをチェーンすることができます

validate1 orElse validate2 orElse validate3

または、関数に変換された検証メソッドのコレクションに対してフォールドを実行できます

val vlist= List(validate1 _, validate2 _, validate3 _)

vlist.foldLeft(None: Option[String]) {(a, b) => if (a == None) b() else a}
于 2010-11-15T13:19:43.973 に答える
3

scalazライブラリには と呼ばれる型がありValidation、エラーと成功の両方を構築することで、いくつかの信じられないほどの体操を可能にします。たとえば、失敗メッセージまたは成功した結果 (A/B/C) を返すメソッドがいくつかあるとします。

import scalaz._; import Scalaz._
def fooA : ValidationNEL[String, A]
def fooB : ValidationNEL[String, B]
def fooC : ValidationNEL[String, C]

これらを applicative functor と共に使用して、呼び出しを連鎖させることができます。

(foo1 <|**|> (foo2, foo3)) match {
  case Success( (a, b, c) ) => //woot
  case Failure(msgs)        => //erk
}

いずれかがfoo1/2/3失敗すると、構成全体が失敗し、失敗メッセージの非空リスト(NEL) が表示されることに注意してください。複数のエラーが発生した場合は、すべてのエラー メッセージが表示されます。

キラーアプリです。成功と失敗を返す方法の例は次のとおりです。

def foo1 : ValidationNEL[String, Int] = 1.success
def foo2 : ValidationNEL[String, Double] = "some error msg".failNel
于 2010-11-16T10:12:57.263 に答える
2

イテレータを組み合わせて最初の要素を取得することはできませんか? 何かのようなもの:

scala> def validate1: Option[String] = {println("1"); None}
scala> def validate2: Option[String] = {println("2"); Some("error")}
scala> def validate3: Option[String] = {println("3"); None}
scala> (validate1.iterator ++ validate2.iterator ++ validate3.iterator).next
1
2
res5: String = error
于 2010-11-15T12:54:33.350 に答える
0

Lift's Boxを使用すると、 ( Fullie Some)、Empty(ie None) およびFailure(anEmptyが空であり、連鎖できる理由がある)を使用することでメリットが得られると思います。David Pollak は、それを紹介する優れたブログ投稿を持っています。要するに、次のようなことをするかもしれません (テストされていません):

def validate1: Box[String]
def validate2: Box[String]
def validate3: Box[String]
val validation = for (
  validation1 <- validate1 ?~ "error message 1"
  validation2 <- validate2 ?~ "error message 2"
  validation3 <- validate3 ?~ "error message 3"
) yield "overall success message"

Fullこれは元の例よりも短くはありませんが、私の意見では、 での検証が成功し、での検証が失敗した結果で、もう少し論理的Failureです。

ただし、小さくすることはできます。まず、検証関数が returnBox[String]であるため、それらは s 自体を返すことができ、自分自身に変換するFailure必要はありません。EmptyFailure

val validation = for (
  validation1 <- validate1
  validation2 <- validate2
  validation3 <- validate3
) yield "overall success message"

ただし、そうであれば同じものを返し、そうでなければ別のものを返すメソッドBoxもあります。これにより、次のようになります。orBoxFullBox

val 検証 = validate1 または validate2 または validate3

ただし、その行は、最初の失敗ではなく、最初の検証成功で停止します。必要なことを行う別のメソッドを作成することは理にかなっているかもしれませんが (おそらく と呼ばれunlessますか?)、理解のためのアプローチよりもはるかに役立つとは言えません。

ただし、これを行う小さなライブラリの売春斡旋は次のとおりです。

scala> class Unless[T](a: Box[T]) {
     | def unless(b: Box[T]) = {
     | if (a.isEmpty) { a }
     | else b
     | }
     | }
defined class Unless

scala> implicit def b2U[T](b: Box[T]): Unless[T] = new Unless(b)
b2U: [T](b: net.liftweb.common.Box[T])Unless[T]

scala> val a = Full("yes")                                      
a: net.liftweb.common.Full[java.lang.String] = Full(yes)

scala> val b = Failure("no")                                    
b: net.liftweb.common.Failure = Failure(no,Empty,Empty)

scala> val c = Full("yes2")                                     
c: net.liftweb.common.Full[java.lang.String] = Full(yes2)

scala> a unless b
res1: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty)

scala> a unless b unless c
res2: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty)

scala> a unless c unless b
res3: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty)

scala> a unless c
res4: net.liftweb.common.Box[java.lang.String] = Full(yes2)

これは、次のエラーでわかるように、Scala の型システムに関する私の限られた理解に基づく簡単なハックです。

scala> b unless a
<console>:13: error: type mismatch;
 found   : net.liftweb.common.Full[java.lang.String]
 required: net.liftweb.common.Box[T]
       b unless a
                ^

ただし、正しい軌道に乗るにはそれで十分なはずです。

もちろん、Lift ScalaDocsにはBoxに関する詳細情報があります。

于 2010-11-15T14:10:49.973 に答える