Scalaz: how can I accumulate Failures or apply a function to Validations with different types?

后端 未结 1 752
小鲜肉
小鲜肉 2021-01-02 17:23

I have 19 strings that need to be validated into various types. When all validate successfully, I would like to instantiate a class that represents a row of a spreadsheet (w

相关标签:
1条回答
  • Suppose we have a case class (which could have more than twelve members):

    case class Foo(a: Int, b: Char, c: Symbol, d: String)
    

    And that we're representing errors as strings and have defined a type alias for convenience:

    type ErrorOr[A] = ValidationNel[String, A]
    

    We also have some validation results:

    val goodA: ErrorOr[Int] = 1.success
    val goodB: ErrorOr[Char] = 'a'.success
    val goodC: ErrorOr[Symbol] = 'a.success
    val goodD: ErrorOr[String] = "a".success
    
    val badA:  ErrorOr[Int] = "x".failNel
    val badC:  ErrorOr[Symbol] = "y".failNel
    

    Now we can write:

    val foo = (Foo.apply _).curried
    
    val good: ErrorOr[Foo] = goodD <*> (goodC <*> (goodB <*> (goodA map foo)))
    val bad:  ErrorOr[Foo] = goodD <*> (badC  <*> (goodB <*> (badA  map foo)))
    

    Which gives us what we want:

    scala> println(good)
    Success(Foo(1,a,'a,a))
    
    scala> println(bad)
    Failure(NonEmptyList(x, y))
    

    In Haskell this would be much prettier—you'd just write:

    Foo <$> goodA <*> goodB <*> goodC <*> goodD
    

    Scala's weaker type inference requires us to write the arguments in the wrong order, unfortunately.

    0 讨论(0)
提交回复
热议问题