Skip to content

Commit 1caaa2e

Browse files
committed
Converts ValidationCE to use Source overloads
Using Source overloads in the ValidationCE removes a lot of combinatoraly explosive codey when it comes to having MergeSource of different types
1 parent 9bf7d78 commit 1caaa2e

File tree

2 files changed

+39
-53
lines changed

2 files changed

+39
-53
lines changed

src/FsToolkit.ErrorHandling/Validation.fs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,32 @@ module Validation =
1515
Result.ofChoice x
1616
|> ofResult
1717

18-
let apply f x =
18+
let apply f (x : Validation<_,_>) : Validation<_,_> =
1919
match f, x with
2020
| Ok f, Ok x -> Ok (f x)
2121
| Error errs, Ok _ | Ok _, Error errs -> Error errs
2222
| Error errs1, Error errs2 -> Error (errs1 @ errs2)
2323

24-
let retn x = ofResult (Ok x)
24+
let retn x = ok x
25+
26+
let map f (x : Validation<_,_>) : Validation<_,_>= Result.map f x
2527

26-
let map2 f x y =
28+
let map2 f (x : Validation<_,_>) (y : Validation<_,_>) : Validation<_,_> =
2729
apply (apply (retn f) x) y
2830

29-
let map3 f x y z =
31+
let map3 f (x : Validation<_,_>) (y : Validation<_,_>) (z : Validation<_,_>) : Validation<_,_> =
3032
apply (map2 f x y) z
3133

34+
let mapError f (x : Validation<_,_>) : Validation<_,_> =
35+
x |> Result.mapError (List.map f)
36+
37+
let mapErrors f (x : Validation<_,_>) : Validation<_,_> =
38+
x |> Result.mapError (f)
39+
3240
let bind (f : 'a -> Validation<'b, 'err>) (x : Validation<'a,'err>) : Validation<_,_>=
3341
Result.bind f x
3442

35-
let zip x1 x2 : Validation<_,_> =
43+
let zip (x1: Validation<_,_>) (x2 : Validation<_,_>) : Validation<_,_> =
3644
match x1,x2 with
3745
| Ok x1res, Ok x2res -> Ok (x1res, x2res)
3846
| Error e, Ok _ -> Error e

src/FsToolkit.ErrorHandling/ValidationCE.fs

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,11 @@ module ValidationCE =
1111
member inline __.ReturnFrom (result : Validation<'T, 'err>) =
1212
result
1313

14-
member inline _.BindReturn(x: Validation<'T,'U>, f) : Validation<_,_> =
15-
Result.map f x
16-
1714
member inline __.Bind
1815
(result: Validation<'T, 'TError>, binder: 'T -> Validation<'U, 'TError>)
1916
: Validation<'U, 'TError> =
2017
Validation.bind binder result
2118

22-
member inline _.MergeSources(t1: Validation<'T,'U>, t2: Validation<'T1,'U>) : Validation<_,_> =
23-
Validation.zip t1 t2
24-
2519
member this.Zero () : Validation<unit, 'TError> =
2620
this.Return ()
2721

@@ -71,6 +65,19 @@ module ValidationCE =
7165
this.While(enum.MoveNext,
7266
this.Delay(fun () -> binder enum.Current)))
7367

68+
member _.BindReturn(x: Validation<'T,'U>, f) = Validation.map f x
69+
70+
member _.MergeSources(t1: Validation<'T,'U>, t2: Validation<'T1,'U>) = Validation.zip t1 t2
71+
72+
/// <summary>
73+
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
74+
///
75+
/// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder
76+
/// </summary>
77+
/// <param name="result"></param>
78+
/// <returns></returns>
79+
member inline _.Source(result : Validation<_,_>) : Validation<_,_> = result
80+
7481
let validation = ValidationBuilder()
7582

7683
[<AutoOpen>]
@@ -79,45 +86,16 @@ module ValidationCEExtensions =
7986
// Having members as extensions gives them lower priority in
8087
// overload resolution and allows skipping more type annotations.
8188
type ValidationBuilder with
82-
member inline __.ReturnFrom (result : Result<'T, 'err>) =
83-
result
84-
|> Validation.ofResult
85-
86-
member inline __.ReturnFrom (result : Choice<'T, 'err>) =
87-
result
88-
|> Validation.ofChoice
89-
90-
member inline __.Bind
91-
(result: Result<'T, 'TError>, binder: 'T -> Validation<'U, 'TError>)
92-
: Validation<'U, 'TError> =
93-
result
94-
|> Validation.ofResult
95-
|> Validation.bind binder
96-
97-
member inline __.Bind
98-
(result: Choice<'T, 'TError>, binder: 'T -> Validation<'U, 'TError>)
99-
: Validation<'U, 'TError> =
100-
result
101-
|> Validation.ofChoice
102-
|> Validation.bind binder
103-
104-
member inline _.BindReturn(x: Result<'T,'U>, f) : Validation<_,_> =
105-
x |> Validation.ofResult |> Result.map f
106-
member inline _.BindReturn(x: Choice<'T,'U>, f) : Validation<_,_> =
107-
x |> Validation.ofChoice |> Result.map f
108-
109-
member inline _.MergeSources(t1: Validation<'T,'U>, t2: Result<'T1,'U>) : Validation<_,_> =
110-
Validation.zip t1 (Validation.ofResult t2)
111-
member inline _.MergeSources(t1: Result<'T,'U>, t2: Validation<'T1,'U>) : Validation<_,_> =
112-
Validation.zip (Validation.ofResult t1) t2
113-
member inline _.MergeSources(t1: Result<'T,'U>, t2: Result<'T1,'U>) : Validation<_,_> =
114-
Validation.zip (Validation.ofResult t1) (Validation.ofResult t2)
115-
116-
117-
member inline _.MergeSources(t1: Validation<'T,'U>, t2: Choice<'T1,'U>) : Validation<_,_> =
118-
Validation.zip t1 (Validation.ofChoice t2)
119-
member inline _.MergeSources(t1: Choice<'T,'U>, t2: Validation<'T1,'U>) : Validation<_,_> =
120-
Validation.zip (Validation.ofChoice t1) t2
121-
member inline _.MergeSources(t1: Choice<'T,'U>, t2: Choice<'T1,'U>) : Validation<_,_> =
122-
Validation.zip (Validation.ofChoice t1) (Validation.ofChoice t2)
123-
89+
/// <summary>
90+
/// Needed to allow `for..in` and `for..do` functionality
91+
/// </summary>
92+
member inline __.Source(s: #seq<_>) = s
93+
/// <summary>
94+
/// Needed to allow `for..in` and `for..do` functionality
95+
/// </summary>
96+
member inline __.Source(s: Result<'T, 'Error>) = Validation.ofResult s
97+
/// <summary>
98+
/// Method lets us transform data types into our internal representation.
99+
/// </summary>
100+
/// <returns></returns>
101+
member inline _.Source(choice : Choice<_,_>) = Validation.ofChoice choice

0 commit comments

Comments
 (0)