Skip to content

Commit a446547

Browse files
Jimmy ByrdTheAngryByrd
authored andcommitted
Convert JobResultCE to use Source overload
1 parent 86b24a8 commit a446547

File tree

2 files changed

+64
-192
lines changed

2 files changed

+64
-192
lines changed

src/FsToolkit.ErrorHandling.JobResult/JobResultCE.fs

Lines changed: 55 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,11 @@ module JobResultCE =
1212
member __.Return (value: 'T) : Job<Result<'T, 'TError>> =
1313
job.Return <| result.Return value
1414

15-
member inline __.ReturnFrom
16-
(asyncResult: Async<Result<'T, 'TError>>)
17-
: Job<Result<'T, 'TError>> =
18-
asyncResult |> Job.fromAsync
19-
2015
member inline __.ReturnFrom
2116
(jobResult: Job<Result<'T, 'TError>>)
2217
: Job<Result<'T, 'TError>> =
2318
jobResult
2419

25-
member inline __.ReturnFrom
26-
(taskResult: Task<Result<'T, 'TError>>)
27-
: Job<Result<'T, 'TError>> =
28-
Job.awaitTask taskResult
29-
30-
member inline __.ReturnFrom
31-
(taskResult: unit -> Task<Result<'T, 'TError>>)
32-
: Job<Result<'T, 'TError>> =
33-
Job.fromTask taskResult
34-
35-
member inline __.ReturnFrom
36-
(result: Result<'T, 'TError>)
37-
: Job<Result<'T, 'TError>> =
38-
job.Return result
39-
40-
member inline __.ReturnFrom
41-
(result: Choice<'T, 'TError>)
42-
: Job<Result<'T, 'TError>> =
43-
result
44-
|> Result.ofChoice
45-
|> __.ReturnFrom
46-
4720
member __.Zero () : Job<Result<unit, 'TError>> =
4821
job.Return <| result.Zero ()
4922

@@ -57,33 +30,6 @@ module JobResultCE =
5730
| Ok x -> return! binder x
5831
| Error x -> return Error x
5932
}
60-
member inline this.Bind
61-
(asyncResult: Async<Result<'T, 'TError>>,
62-
binder: 'T -> Job<Result<'U, 'TError>>)
63-
: Job<Result<'U, 'TError>> =
64-
this.Bind(Job.fromAsync asyncResult, binder)
65-
66-
member inline this.Bind
67-
(taskResult: Task<Result<'T, 'TError>>,
68-
binder: 'T -> Job<Result<'U, 'TError>>)
69-
: Job<Result<'U, 'TError>> =
70-
this.Bind(Job.awaitTask taskResult, binder)
71-
72-
member inline this.Bind
73-
(taskResult: unit -> Task<Result<'T, 'TError>>,
74-
binder: 'T -> Job<Result<'U, 'TError>>)
75-
: Job<Result<'U, 'TError>> =
76-
this.Bind(Job.fromTask taskResult, binder)
77-
78-
member inline this.Bind
79-
(result: Result<'T, 'TError>, binder: 'T -> Job<Result<'U, 'TError>>)
80-
: Job<Result<'U, 'TError>> =
81-
this.Bind(this.ReturnFrom result, binder)
82-
83-
member inline this.Bind
84-
(result: Choice<'T, 'TError>, binder: 'T -> Job<Result<'U, 'TError>>)
85-
: Job<Result<'U, 'TError>> =
86-
this.Bind(this.ReturnFrom result, binder)
8733

8834
member __.Delay
8935
(generator: unit -> Job<Result<'T, 'TError>>)
@@ -139,143 +85,70 @@ module JobResultCE =
13985
this.While(enum.MoveNext,
14086
this.Delay(fun () -> binder enum.Current)))
14187

142-
143-
14488
member inline __.BindReturn(x: Job<Result<'T,'U>>, f) = JobResult.map f x
145-
member inline __.BindReturn(x: Async<Result<'T,'U>>, f) = __.BindReturn(x |> Job.fromAsync, f)
146-
member inline __.BindReturn(x: Async<Choice<'T,'U>>, f) = __.BindReturn(x |> Async.map Result.ofChoice, f)
147-
member inline __.BindReturn(x: Result<'T,'U>, f) = __.BindReturn(x |> Job.singleton, f)
148-
member inline __.BindReturn(x: Choice<'T,'U>, f) = __.BindReturn(x |> Result.ofChoice |> Job.singleton, f)
149-
member inline __.BindReturn(x: Task<Result<'T,'U>>, f) = __.BindReturn(x |> Job.awaitTask, f)
89+
member inline __.MergeSources(t1: Job<Result<'T,'U>>, t2: Job<Result<'T1,'U>>) = JobResult.zip t1 t2
15090

91+
/// <summary>
92+
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
93+
///
94+
/// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder
95+
/// </summary>
96+
member inline _.Source(job' : Job<Result<_,_>>) : Job<Result<_,_>> = job'
15197

152-
member inline __.MergeSources(t1: Job<Result<'T,'U>>, t2: Job<Result<'T1,'U>>) = JobResult.zip t1 t2
153-
member inline __.MergeSources(t1: Task<Result<'T,'U>>, t2: Task<Result<'T1,'U>>) = JobResult.zip (Job.awaitTask t1) (Job.awaitTask t2)
154-
member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Async<Result<'T1,'U>>) = JobResult.zip (Job.fromAsync t1) (Job.fromAsync t2)
98+
/// <summary>
99+
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
100+
/// </summary>
101+
member inline _.Source(task : Task<Result<_,_>>) : Job<Result<_,_>> = task |> Job.awaitTask
155102

103+
/// <summary>
104+
/// Method lets us transform data types into our internal representation.
105+
/// </summary>
106+
member inline _.Source(result : Async<Result<_,_>>) : Job<Result<_,_>> = result |> Job.fromAsync
156107

108+
let jobResult = JobResultBuilder()
157109

158110
[<AutoOpen>]
159111
module JobResultCEExtensions =
160112
open Hopac
161-
// Having Job<_> members as extensions gives them lower priority in
113+
// Having members as extensions gives them lower priority in
162114
// overload resolution between Job<_> and Job<Result<_,_>>.
163115
type JobResultBuilder with
164116

165-
member inline __.ReturnFrom (job': Job<'T>) : Job<Result<'T, 'TError>> =
166-
job {
167-
let! x = job'
168-
return Ok x
169-
}
170-
171-
member inline __.ReturnFrom (async': Async<'T>) : Job<Result<'T, 'TError>> =
172-
job {
173-
let! x = async' |> Job.fromAsync
174-
return Ok x
175-
}
176-
177-
member inline __.ReturnFrom (task: Task<'T>) : Job<Result<'T, 'TError>> =
178-
job {
179-
let! x = task
180-
return Ok x
181-
}
182-
183-
member inline __.ReturnFrom (task: unit -> Task<'T>) : Job<Result<'T, 'TError>> =
184-
job {
185-
let! x = task |> Job.fromTask
186-
return Ok x
187-
}
188-
189-
member inline __.ReturnFrom (task: Task) : Job<Result<unit, 'TError>> =
190-
job {
191-
do! Job.awaitUnitTask task
192-
return result.Zero ()
193-
}
194-
195-
member inline this.Bind
196-
(job': Job<'T>, binder: 'T -> Job<Result<'U, 'TError>>)
197-
: Job<Result<'U, 'TError>> =
198-
let jResult = job {
199-
let! x = job'
200-
return Ok x
201-
}
202-
this.Bind(jResult, binder)
203-
204-
member inline this.Bind
205-
(task: Async<'T>, binder: 'T -> Job<Result<'U, 'TError>>)
206-
: Job<Result<'U, 'TError>> =
207-
this.Bind(Job.fromAsync task, binder)
208-
209-
member inline this.Bind
210-
(task: Task<'T>, binder: 'T -> Job<Result<'U, 'TError>>)
211-
: Job<Result<'U, 'TError>> =
212-
this.Bind(Job.awaitTask task, binder)
213-
214-
member inline this.Bind
215-
(task: unit -> Task<'T>, binder: 'T -> Job<Result<'U, 'TError>>)
216-
: Job<Result<'U, 'TError>> =
217-
this.Bind(Job.fromTask task, binder)
218-
219-
member inline this.Bind
220-
(task: Task, binder: unit -> Job<Result<'T, 'TError>>)
221-
: Job<Result<'T, 'TError>> =
222-
this.Bind(Job.awaitUnitTask task, binder)
223-
224-
member inline __.BindReturn(x: Job<'T>, f) =
225-
__.BindReturn(x |> Job.map Result.Ok, f)
226-
member inline __.BindReturn(x: Async<'T>, f) =
227-
__.BindReturn(x |> Async.map Result.Ok, f)
228-
member inline __.BindReturn(x: Task<'T>, f) =
229-
__.BindReturn(x |> Task.map Result.Ok, f)
230-
member inline __.BindReturn(x: Task, f) =
231-
__.BindReturn(x |> Task.ofUnit |> Task.map Result.Ok, f)
232-
233-
234-
235-
member inline __.MergeSources(t1: Job<Result<'T,'U>>, t2: Async<Result<'T1,'U>>) = JobResult.zip (t1) (t2 |> Job.fromAsync)
236-
member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Job<Result<'T1,'U>>) = JobResult.zip (t1 |> Job.fromAsync) (t2)
237-
238-
239-
member inline __.MergeSources(t1: Job<Result<'T,'U>>, t2: Task<Result<'T1,'U>>) = JobResult.zip (t1) (t2 |> Job.awaitTask)
240-
member inline __.MergeSources(t1: Task<Result<'T,'U>>, t2: Job<Result<'T1,'U>>) = JobResult.zip (t1 |> Job.awaitTask) (t2)
241-
242-
member inline __.MergeSources(t1: Task<Result<'T,'U>>, t2: Async<Result<'T1,'U>>) = AsyncResult.zip (t1 |> Async.AwaitTask) (t2) |> Job.fromAsync
243-
member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Task<Result<'T1,'U>>) = AsyncResult.zip (t1) (t2 |> Async.AwaitTask) |> Job.fromAsync
244-
245-
member inline __.MergeSources(t1: Task<Result<'T,'U>>, t2: Result<'T1,'U>) = AsyncResult.zip (t1 |> Async.AwaitTask) (t2 |> Async.singleton) |> Job.fromAsync
246-
member inline __.MergeSources(t1: Result<'T,'U>, t2: Task<Result<'T1,'U>>) = AsyncResult.zip (t1 |> Async.singleton) (t2 |> Async.AwaitTask) |> Job.fromAsync
247-
248-
249-
member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Async<'T1>) = AsyncResult.zip t1 (t2 |> Async.map Result.Ok) |> Job.fromAsync
250-
member inline __.MergeSources(t1: Async<'T>, t2: Async<Result<'T1,'U>>) = AsyncResult.zip (t1 |> Async.map Result.Ok) t2 |> Job.fromAsync
251-
252-
member inline __.MergeSources(t1: Job<Result<'T,'U>>, t2: Result<'T1,'U>) = JobResult.zip t1 (t2 |> Job.singleton)
253-
member inline __.MergeSources(t1: Result<'T,'U>, t2: Job<Result<'T1,'U>>) = JobResult.zip (t1 |> Job.singleton) t2
254-
member inline __.MergeSources(t1: Result<'T,'U>, t2: Result<'T1,'U>) = AsyncResult.zip (t1 |> Async.singleton) (t2 |> Async.singleton) |> Job.fromAsync
255-
256-
member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Result<'T1,'U>) = AsyncResult.zip t1 (t2 |> Async.singleton) |> Job.fromAsync
257-
member inline __.MergeSources(t1: Result<'T,'U>, t2: Async<Result<'T1,'U>>) = AsyncResult.zip (t1 |> Async.singleton) t2 |> Job.fromAsync
258-
259-
260-
member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Choice<'T1,'U>) = AsyncResult.zip t1 (t2 |> Result.ofChoice |> Async.singleton) |> Job.fromAsync
261-
member inline __.MergeSources(t1: Choice<'T,'U>, t2: Async<Result<'T1,'U>>) = AsyncResult.zip (t1 |> Result.ofChoice |> Async.singleton) t2 |> Job.fromAsync
262-
263-
member inline __.MergeSources(t1: Job<Result<'T,'U>>, t2: Choice<'T1,'U>) = JobResult.zip t1 (t2 |> Result.ofChoice |> Job.singleton)
264-
member inline __.MergeSources(t1: Choice<'T,'U>, t2: Job<Result<'T1,'U>>) = JobResult.zip (t1 |> Result.ofChoice |> Job.singleton) t2
265-
member inline __.MergeSources(t1: Choice<'T,'U>, t2: Choice<'T1,'U>) = AsyncResult.zip (t1 |> Result.ofChoice |> Async.singleton) (t2 |> Result.ofChoice |> Async.singleton) |> Job.fromAsync
266-
267-
member inline __.MergeSources(t1: Choice<'T,'U>, t2: Result<'T1,'U>) = AsyncResult.zip (t1 |> Result.ofChoice |> Async.singleton) (t2 |> Async.singleton) |> Job.fromAsync
268-
member inline __.MergeSources(t1: Result<'T,'U>, t2: Choice<'T1,'U>) = AsyncResult.zip (t1 |> Async.singleton) (t2 |> Result.ofChoice |> Async.singleton) |> Job.fromAsync
269-
270-
271-
[<AutoOpen>]
272-
module JobResultCEExtensions2 =
273-
// Having Async<_> members as extensions gives them lower priority in
274-
// overload resolution between Async<_> and Async<Result<_,_>>.
275-
type JobResultBuilder with
276-
member inline __.MergeSources(t1: Job<'T>, t2: Job<'T1>) = JobResult.zip (t1 |> Job.map Result.Ok) (t2 |> Job.map Result.Ok)
277-
member inline __.MergeSources(t1: Async<'T>, t2: Async<'T1>) = AsyncResult.zip (t1 |> Async.map Result.Ok) (t2 |> Async.map Result.Ok) |> Job.fromAsync
278-
member inline __.MergeSources(t1: Task<'T>, t2: Task<'T1>) = TaskResult.zip (t1 |> Task.map Result.Ok) (t2 |> Task.map Result.Ok) |> Job.awaitTask
279-
280-
281-
let jobResult = JobResultBuilder()
117+
/// <summary>
118+
/// Needed to allow `for..in` and `for..do` functionality
119+
/// </summary>
120+
member inline __.Source(s: #seq<_>) = s
121+
122+
/// <summary>
123+
/// Method lets us transform data types into our internal representation.
124+
/// </summary>
125+
member inline _.Source(result : Result<_,_>) : Job<Result<_,_>> = Job.result result
126+
127+
/// <summary>
128+
/// Method lets us transform data types into our internal representation.
129+
/// </summary>
130+
member inline _.Source(choice : Choice<_,_>) : Job<Result<_,_>> =
131+
choice
132+
|> Result.ofChoice
133+
|> Job.result
134+
135+
/// <summary>
136+
/// Method lets us transform data types into our internal representation.
137+
/// </summary>
138+
member inline __.Source(job' : Job<_>) : Job<Result<_,_>> = job' |> Job.map Ok
139+
140+
/// <summary>
141+
/// Method lets us transform data types into our internal representation.
142+
/// </summary>
143+
member inline __.Source(asyncComputation : Async<_>) : Job<Result<_,_>> = asyncComputation |> Job.fromAsync |> Job.map Ok
144+
145+
/// <summary>
146+
/// Method lets us transform data types into our internal representation.
147+
/// </summary>
148+
member inline _.Source(task : Task<_>) : Job<Result<_,_>> = task |> Job.awaitTask |> Job.map Ok
149+
150+
/// <summary>
151+
/// Method lets us transform data types into our internal representation.
152+
/// </summary>
153+
member inline _.Source(t : Task) : Job<Result<_,_>> = t |> Job.awaitUnitTask |> Job.map Ok
154+

tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultCE.fs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -331,16 +331,15 @@ let ``AsyncResultCE applicative tests`` =
331331
Expect.equal actual (Ok 4) "Should be ok"
332332
}
333333

334-
// Cannot get this to compile properly
335-
// testCaseJob "Happy Path Async" <| job {
336-
// let! actual = jobResult {
337-
// let! a = Async.singleton 3 //: Async<int>
338-
// and! b = Async.singleton 2 //: Async<int>
339-
// and! c = Async.singleton 1 //: Async<int>
340-
// return a + b - c
341-
// }
342-
// Expect.equal actual (Ok 4) "Should be ok"
343-
// }
334+
testCaseJob "Happy Path Async" <| job {
335+
let! actual = jobResult {
336+
let! a = Async.singleton 3 //: Async<int>
337+
and! b = Async.singleton 2 //: Async<int>
338+
and! c = Async.singleton 1 //: Async<int>
339+
return a + b - c
340+
}
341+
Expect.equal actual (Ok 4) "Should be ok"
342+
}
344343

345344
testCaseJob "Happy Path 2 Async" <| job {
346345
let! actual = jobResult {

0 commit comments

Comments
 (0)