2017-04-04 47 views
1

我想依次驗證字符串列表和定義驗證結果類型這樣的:如何讓它成爲monad?

import cats._, cats.data._, cats.implicits._ 

case class ValidationError(msg: String) 
type ValidationResult[A] = Either[NonEmptyList[ValidationError], A] 
type ListValidationResult[A] = ValidationResult[List[A]] // not a monad :(

我想作ListValidationResult一個單子。我應該手動執行flatMappure還是有更簡單的方法?

回答

1

我建議你採取了完全不同的方法利用catsValidated

import cats.data.Validated.{ invalidNel, valid } 

val stringList: List[String] = ??? 

def evaluateString(s: String): ValidatedNel[ValidationError, String] = 
    if (???) valid(s) else invalidNel(ValidationError(s"invalid $s")) 

val validationResult: ListValidationResult[String] = 
    stringList.map(evaluateString).sequenceU.toEither 

它可以適用於泛型類型T,按你的例子​​。


注:

  • val stringList: List[String] = ???是要驗證字符串列表;
  • ValidatedNel[A,B]只是Validated[NonEmptyList[A],B]的類型別名;
  • evaluateString應該是你的評價函數,它目前只是一個未實現的存根if;
  • sequenceU您可能想要閱讀有關它的文件catssequenceU;
  • toEither完全符合您的想法,它將Validated[A,B]轉換爲Either[A,B]

正如@邁克爾指出的那樣,你也可以使用traverseU,而不是mapsequenceU

val validationResult: ListValidationResult[String] = 
    stringList.traverseU(evaluateString).toEither 
+1

哦,謝謝。我忘了它。可以使用'traverse'(或'traverseU')來代替'map'和'sequence'('sequenceU')。 – Michael

+0

我需要澄清我的問題:假設我需要確保輸入''a「',''b」'和'多個「c」'。假設你有三個函數:'String => ValidatedNel [ValidationError,String]'來檢查給定的字符串是「a」,「b」還是「c」。你將如何驗證列表? – Michael

+0

我可能會寫另一個關於它的問題。 – Michael