I have a scenario the user creates n objects. If all objects are valid I want to get all the objects, if any one of them is invalid, I want to get all the errors, something like:
Validation<'a, 'b> list -> Validation<'a list, 'b list>.
I'm posting this here as it might be a common scenario.
Based on @gusty's comment on a previous issue, I ended up with:
let f (vs : Validation<_, _> list): Validation<_ list, _> = traverse (first result) vs
(it needed a little more help with the types.)
Which gives me the behaviour I would expect:
let private f (vs : Validation<_, _> list): Validation<_ list, _> = traverse (first result) vs
[<Fact>]
let ``My test`` () =
let x1 : Validation<string, _> list = [ Success 1; Success 2; Success 3 ]
let e1 : Validation<string list, _> = Success [ 1; 2; 3 ]
let x2 = [ Success 1; Failure "a"; Success 3 ]
let e2 : Validation<_, int list> = Failure [ "a" ]
let x3 : Validation<_, int> list = [ Failure "a"; Failure "b"; Failure "c" ]
let e3 : Validation<_, int list> = Failure [ "a"; "b"; "c" ]
test <@ f x1 = e1 @>
test <@ f x2 = e2 @>
test <@ f x3 = e3 @>
Thank you for you help @gusty, @DunetsNM. One slight follow-up, is there an appropriate name for this function?
Originally posted here: https://github.com/fsprojects/FSharpPlus/issues/51#issuecomment-586202997
Looks like Biapplicative has such function: http://hackage.haskell.org/package/bifunctors-5.5.7/docs/Data-Biapplicative.html#v:sequenceBia in its generic form.
Perfect, thank you @gusty!
One more tip:
If you don't write a generic result F# is able to infer the whole function.
traverse (first List.singleton) vs so you don't need to pre-create the function.
We might add Bitraversable and Biapplicative to the library.
Bitraversable is almost there as many extensions have bisquence and bitraverse already.
@gusty am I right in thinking that bisequence might help me (a,b) list -> (a list, b list)?
Ahh, I see you've done this already! I'm guessing this would be it:
https://github.com/fsprojects/FSharpPlus/commit/210a1674b15abe23f7d7d9ea9eadc112b786a517#diff-c19e480c6c67a51ba176ac6cc88f08abR15
Well, your signature goes the other way around. It looks rather like unzip.
But if you want to go back you can use bisequence which was just added and will be shipped in RC4:
> [(2, 5)] |> unzip ;;
val it : int list * int list = ([2], [5])
> it |> bisequence ;;
val it : (int * int) list = [(2, 5)]
Oh man, you're too quick, I just came back to edit my comment because I realized it was the other way around 馃槄
Thank you though!
No worries.
Also, note that (x |> bisequence) === (x ||> lift2 tuple2) for 2-uples
Ohh, excellent, that'll be handy till RC4