मैं स्काला सीख रहा हूं और आज Scalaz ValidationNel का उपयोग करके Fail Slow तंत्र में आया हूं, हालांकि यह समझना वास्तव में मुश्किल है कि इसका उपयोग कैसे किया जाए। मैं ये ब्लॉग पढ़ रहा हूं: Blog1, मैं पढ़ रहा हूं यह स्टैक ओवरफ्लो पोस्ट भी: StackOverflow लेकिन गैर-कार्यात्मक प्रोग्रामर के लिए इसे समझना वास्तव में कठिन है। क्या कोई स्कैला में ValidationNel में त्रुटियों को जमा करने के बारे में एक साधारण उदाहरण प्रदान कर सकता है? उदाहरण के बारे में भी विवरण देना वास्तव में सहायक होगा।

2
Explorer 4 अक्टूबर 2017, 00:26

2 जवाब

सबसे बढ़िया उत्तर

आपके द्वारा लिंक किए गए ब्लॉग के उदाहरण का उपयोग करना

val sumV: ValidationNEL[String, Int] = for {
  a <- 42.successNel[String]
  b <- "Boo".failNel[Int]
  c <- "Wah wah".failNel[Int] // by defn of flatMap, can't get here
} yield a + b + c

यह क्या कर रहा है विभिन्न कार्यों को एक साथ श्रृंखलाबद्ध करने के लिए एक फ्लैटमैप का उपयोग कर रहा है। 42.successNel[String], उदाहरण के लिए, एक Success बनाता है, और "Boo"failNel[Int] एक विफलता बनाता है। फ़्लैटमैप जिस तरह से यहां काम करता है, वह अगले ऑपरेशन को केवल एक सफलता पर जारी रखना है। तो यह एक "फेल फास्ट" ऑपरेशन है - यह आपके त्रुटि मामले में पहली विफलता को इकट्ठा करता है और बंद हो जाता है।

यदि आप "धीमी गति से विफल" करना चाहते हैं - अर्थात। सभी संभावित विफलताओं को इकट्ठा करें, आपको एक अलग विधि का उपयोग करने की आवश्यकता है। यही वह जगह है जहां आवेदक आता है।

val yes = 3.14.successNel[String]
val doh = "Error".failNel[Double]

def addTwo(x: Double, y: Double) = x + y

(yes |@| yes)(addTwo) // Success(6.28)
(doh |@| doh)(addTwo) // Failure(NonEmptyList(Error, Error))

(a |@| b)(someFunctionOfTwoArgsHere) - यह जो कह रहा है वह है "'ए' ऑपरेशन करें, और 'बी' ऑपरेशन करें, और यदि दोनों सफल हों, तो कुछ फंक्शनऑफ टूआर्ग यहां (ए, बी) करें। अन्यथा, कोई भी विफलता लें और उन्हें मिलाएं। तो यदि कोई विफल रहता है, लेकिन बी सफल होता है, तो आपको असफल होने के परिणाम के साथ सत्यापन विफलता मिलती है। यदि ए और बी विफल रहता है, तो आपको ए और बी दोनों के असफल होने के परिणामों के साथ सत्यापन विफलता मिलती है।

1
Ren 5 अक्टूबर 2017, 02:09

पिछला उत्तर अच्छा है लेकिन मैं समझता हूं कि आप ओओपी प्रतिमान से आते हैं इसलिए मुझे दोनों प्रतिमानों की तुलना करते हुए एक और उदाहरण देना चाहिए।

सामान्य कोड:

val a = "1"
val b = "aaa"
val c = "bbb"

def isAllDigits(x: String) = x forall Character.isDigit
def appendError(x: String, errors: mutable.Buffer[String]) = errors += s"$x is not number"

type Errors = NonEmptyList[String]

// disjunction \/ for fail fast
def toDigitFailFast(x: String): Errors \/ Int = {
  if (isAllDigits(x)) {
    x.toInt.right
  } else {
    s"$x is not number".wrapNel.left
  }
}

// validation nel (non empty list) for fail slow
def toDigitFS(x: String): ValidationNel[String, Int] = {
  if (x forall Character.isDigit) {
    x.toInt.successNel
  } else {
    s"$x is not number".failureNel
  }
}

असफल तेज़ अनिवार्यता के लिए कोड:

// fail fast imperative programming
println("---\nFail Fast imperative")
val failFastErrors = mutable.Buffer.empty[String]

if(isAllDigits(a)) {
  if(isAllDigits(b)) {
    if(isAllDigits(c)) {
      val total = a.toInt + b.toInt + c.toInt
      println(s"Total = ${total}!!")
    } else {
      appendError(c, failFastErrors)
    }
  } else {
    appendError(b, failFastErrors)
  }
} else {
  appendError(a, failFastErrors)
}

if(failFastErrors.nonEmpty) {
  println("Errors:")
  for(error <- failFastErrors) {
    println(error)
  }
}

तेजी से कार्यात्मक विफल होने के लिए कोड (वियोजन के साथ /):

val resultFunc = for {
  x <- toDigitFailFast(a)
  y <- toDigitFailFast(b)
  z <- toDigitFailFast(c)
} yield (x + y + z)

resultFunc match {
  case \/-(total) => println(s"Total = $total")
  case -\/(errors) =>
    println("Errors:")
    errors.foreach(println)
}

तेजी से विफल होने पर आउटपुट (केवल आपको पहली त्रुटि बताता है):

Fail Fast imperative
Errors:
aaa is not number
Fail Fast functional
Errors:
aaa is not number

अब अनिवार्य के लिए असफल धीमा कोड:

// fail slow imperative programming
println("---\nFail Slow imperative")
val failSlowErrors = mutable.Buffer.empty[String]

if(!isAllDigits(a)) {
  appendError(a, failSlowErrors)
}
if(!isAllDigits(b)) {
  appendError(b, failSlowErrors)
}
if(!isAllDigits(c)) {
  appendError(c, failSlowErrors)
}

if(failSlowErrors.isEmpty) {
  val total = a.toInt + b.toInt + c.toInt
  println(s"Total = ${total}!!")
} else {
  println("Errors:")
  for(error <- failSlowErrors) {
    println(error)
  }
}

और कार्यात्मक संस्करण (धीमी गति से विफल):

// fail slow functional programming
println("---\nFail Slow functional")


val resultFuncSlow = 
  (toDigitFS(a) |@| toDigitFS(b) |@| toDigitFS(c)) { _ + _ + _ }

resultFuncSlow match {
  case Success(result) => println(result)
  case Failure(errors) =>
    println("Errors:")
    errors.foreach(println)
}

और दोनों त्रुटियों के साथ आउटपुट:

Fail Slow imperative
Errors:
aaa is not number
bbb is not number
---
Fail Slow functional
Errors:
aaa is not number
bbb is not number
0
Carlos Verdes 9 मई 2019, 18:44