Skip to content

Commit ab98b1d

Browse files
authored
Extend Option.either (#198)
1 parent dec6d9a commit ab98b1d

File tree

10 files changed

+190
-5
lines changed

10 files changed

+190
-5
lines changed

src/FsToolkit.ErrorHandling.JobResult/JobOption.fs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,25 @@ module JobOption =
2323

2424
let inline apply f x =
2525
bind (fun f' -> bind (fun x' -> retn (f' x')) x) f
26+
27+
28+
/// <summary>
29+
/// Returns result of running <paramref name="onSome"/> if it is <c>Some</c>, otherwise returns result of running <paramref name="onNone"/>
30+
/// </summary>
31+
/// <param name="onSome">The function to run if <paramref name="input"/> is <c>Some</c></param>
32+
/// <param name="onNone">The function to run if <paramref name="input"/> is <c>None</c></param>
33+
/// <param name="input">The input option.</param>
34+
/// <returns>
35+
/// The result of running <paramref name="onSome"/> if the input is <c>Some</c>, else returns result of running <paramref name="onNone"/>.
36+
/// </returns>
37+
let inline either
38+
([<InlineIfLambda>] onSome: 'input -> Job<'output>)
39+
(onNone: Job<'output>)
40+
(input: Job<'input option>)
41+
: Job<'output> =
42+
input
43+
|> Job.bind (
44+
function
45+
| Some v -> onSome v
46+
| None -> onNone
47+
)

src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,25 @@ module TaskOption =
3030
let inline zip x1 x2 =
3131
Task.zip x1 x2
3232
|> Task.map (fun (r1, r2) -> Option.zip r1 r2)
33+
34+
35+
/// <summary>
36+
/// Returns result of running <paramref name="onSome"/> if it is <c>Some</c>, otherwise returns result of running <paramref name="onNone"/>
37+
/// </summary>
38+
/// <param name="onSome">The function to run if <paramref name="input"/> is <c>Some</c></param>
39+
/// <param name="onNone">The function to run if <paramref name="input"/> is <c>None</c></param>
40+
/// <param name="input">The input option.</param>
41+
/// <returns>
42+
/// The result of running <paramref name="onSome"/> if the input is <c>Some</c>, else returns result of running <paramref name="onNone"/>.
43+
/// </returns>
44+
let inline either
45+
([<InlineIfLambda>] onSome: 'input -> Task<'output>)
46+
([<InlineIfLambda>] onNone: unit -> Task<'output>)
47+
(input: Task<'input option>)
48+
: Task<'output> =
49+
input
50+
|> Task.bind (
51+
function
52+
| Some v -> onSome v
53+
| None -> onNone ()
54+
)

src/FsToolkit.ErrorHandling/AsyncOption.fs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,24 @@ module AsyncOption =
3131
(input: Async<'input option>)
3232
: Async<'output option> =
3333
bind (fun f' -> bind (fun x' -> retn (f' x')) input) applier
34+
35+
/// <summary>
36+
/// Returns result of running <paramref name="onSome"/> if it is <c>Some</c>, otherwise returns result of running <paramref name="onNone"/>
37+
/// </summary>
38+
/// <param name="onSome">The function to run if <paramref name="input"/> is <c>Some</c></param>
39+
/// <param name="onNone">The function to run if <paramref name="input"/> is <c>None</c></param>
40+
/// <param name="input">The input option.</param>
41+
/// <returns>
42+
/// The result of running <paramref name="onSome"/> if the input is <c>Some</c>, else returns result of running <paramref name="onNone"/>.
43+
/// </returns>
44+
let inline either
45+
([<InlineIfLambda>] onSome: 'input -> Async<'output>)
46+
(onNone: Async<'output>)
47+
(input: Async<'input option>)
48+
: Async<'output> =
49+
input
50+
|> Async.bind (
51+
function
52+
| Some v -> onSome v
53+
| None -> onNone
54+
)

src/FsToolkit.ErrorHandling/Option.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ module Option =
130130
/// <returns>
131131
/// The result of running <paramref name="onSome"/> if the input is <c>Some</c>, else returns result of running <paramref name="onNone"/>.
132132
/// </returns>
133+
[<System.Obsolete("Call Option.either instead.", true)>]
133134
let inline maybe
134135
([<InlineIfLambda>] onNone: unit -> 'output)
135136
([<InlineIfLambda>] onSome: 'a -> 'output)
@@ -138,3 +139,21 @@ module Option =
138139
match input with
139140
| Some x -> onSome x
140141
| None -> onNone ()
142+
143+
/// <summary>
144+
/// Returns result of running <paramref name="onSome"/> if it is <c>Some</c>, otherwise returns result of running <paramref name="onNone"/>
145+
/// </summary>
146+
/// <param name="onSome">The function to run if <paramref name="input"/> is <c>Some</c></param>
147+
/// <param name="onNone">The function to run if <paramref name="input"/> is <c>None</c></param>
148+
/// <param name="input">The input option.</param>
149+
/// <returns>
150+
/// The result of running <paramref name="onSome"/> if the input is <c>Some</c>, else returns result of running <paramref name="onNone"/>.
151+
/// </returns>
152+
let inline either
153+
([<InlineIfLambda>] onSome: 'a -> 'output)
154+
([<InlineIfLambda>] onNone: unit -> 'output)
155+
(input: 'a option)
156+
: 'output =
157+
match input with
158+
| Some x -> onSome x
159+
| None -> onNone ()

src/FsToolkit.ErrorHandling/ValueOption.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,23 @@ module ValueOption =
124124
|> ofNull
125125
| ValueNone -> ValueNone
126126

127+
128+
/// <summary>
129+
/// Returns result of running <paramref name="onSome"/> if it is <c>ValueSome</c>, otherwise returns result of running <paramref name="onNone"/>
130+
/// </summary>
131+
/// <param name="onSome">The function to run if <paramref name="input"/> is <c>ValueSome</c></param>
132+
/// <param name="onNone">The function to run if <paramref name="input"/> is <c>ValueNone</c></param>
133+
/// <param name="input">The input option.</param>
134+
/// <returns>
135+
/// The result of running <paramref name="onSome"/> if the input is <c>ValueSome</c>, else returns result of running <paramref name="onNone"/>.
136+
/// </returns>
137+
let inline either
138+
([<InlineIfLambda>] onSome: 'a -> 'output)
139+
([<InlineIfLambda>] onNone: unit -> 'output)
140+
(input: 'a voption)
141+
: 'output =
142+
match input with
143+
| ValueSome x -> onSome x
144+
| ValueNone -> onNone ()
145+
127146
#endif

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ let jobOptionOperatorTests =
118118
|> Expect.hasJobSomeValue (PostId newPostId)
119119
]
120120

121+
122+
let eitherTests =
123+
testList "JobOption.either Tests" [
124+
testCaseJob "Some"
125+
<| job {
126+
let value1 = JobOption.retn 5
127+
let f = job.Return 42
128+
let add2 x = job { return x + 2 }
129+
let! result = (JobOption.either add2 f value1)
130+
Expect.equal result 7 ""
131+
}
132+
testCaseJob "None"
133+
<| job {
134+
let value1 = job.Return None
135+
let f = job.Return 42
136+
let add2 x = job { return x + 2 }
137+
let! result = (JobOption.either add2 f value1)
138+
Expect.equal result 42 ""
139+
}
140+
]
141+
121142
let allTests =
122143
testList "Job Option Tests" [
123144
mapTests

tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,33 @@ let taskOptionOperatorTests =
127127
|> Expect.hasTaskSomeValue (PostId newPostId)
128128
]
129129

130+
131+
let eitherTests =
132+
testList "TaskOption.either Tests" [
133+
testCaseTask "Some"
134+
<| fun () -> task {
135+
let value1 = TaskOption.retn 5
136+
let f () = Task.FromResult 42
137+
let add2 x = task { return x + 2 }
138+
let! result = (TaskOption.either add2 f value1)
139+
Expect.equal result 7 ""
140+
}
141+
testCaseTask "None"
142+
<| fun () -> task {
143+
let value1 = Task.FromResult None
144+
let f () = Task.FromResult 42
145+
let add2 x = task { return x + 2 }
146+
let! result = (TaskOption.either add2 f value1)
147+
Expect.equal result 42 ""
148+
}
149+
]
150+
130151
let allTests =
131152
testList "Task Option Tests" [
132153
mapTests
133154
bindTests
134155
applyTests
135156
retnTests
136157
taskOptionOperatorTests
158+
eitherTests
137159
]

tests/FsToolkit.ErrorHandling.Tests/AsyncOption.fs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,32 @@ let asyncOptionOperatorTests =
103103
}
104104
]
105105

106+
let eitherTests =
107+
testList "AsyncOption.either Tests" [
108+
testCaseAsync "Some"
109+
<| async {
110+
let value1 = AsyncOption.retn 5
111+
let f = async.Return 42
112+
let add2 x = async { return x + 2 }
113+
let! result = (AsyncOption.either add2 f value1)
114+
Expect.equal result 7 ""
115+
}
116+
testCaseAsync "None"
117+
<| async {
118+
let value1 = async.Return None
119+
let f = async.Return 42
120+
let add2 x = async { return x + 2 }
121+
let! result = (AsyncOption.either add2 f value1)
122+
Expect.equal result 42 ""
123+
}
124+
]
125+
106126
let allTests =
107127
testList "Async Option Tests" [
108128
mapTests
109129
bindTests
110130
applyTests
111131
retnTests
112132
asyncOptionOperatorTests
133+
eitherTests
113134
]

tests/FsToolkit.ErrorHandling.Tests/Option.fs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,20 +111,20 @@ let bindNullTests =
111111
Expect.equal (Option.bindNull someBinder value1) (None) ""
112112
]
113113

114-
let maybeTests =
115-
testList "Option.maybe Tests" [
114+
let eitherTests =
115+
testList "Option.either Tests" [
116116
testCase "Some"
117117
<| fun _ ->
118118
let value1 = Some 5
119119
let f () = 42
120120
let add2 = (+) 2
121-
Expect.equal (Option.maybe f add2 value1) 7 ""
121+
Expect.equal (Option.either add2 f value1) 7 ""
122122
testCase "None"
123123
<| fun _ ->
124124
let value1 = None
125125
let f () = 42
126126
let add2 = (+) 2
127-
Expect.equal (Option.maybe f add2 value1) 42 ""
127+
Expect.equal (Option.either add2 f value1) 42 ""
128128
]
129129

130130
let allTests =
@@ -135,5 +135,5 @@ let allTests =
135135
ofResultTests
136136
ofNullTests
137137
bindNullTests
138-
maybeTests
138+
eitherTests
139139
]

tests/FsToolkit.ErrorHandling.Tests/ValueOption.fs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ let bindNullTests =
114114
Expect.equal (ValueOption.bindNull someBinder value1) (ValueNone) ""
115115
]
116116

117+
118+
let eitherTests =
119+
testList "ValueOption.either Tests" [
120+
testCase "Some"
121+
<| fun _ ->
122+
let value1 = ValueSome 5
123+
let f () = 42
124+
let add2 = (+) 2
125+
Expect.equal (ValueOption.either add2 f value1) 7 ""
126+
testCase "None"
127+
<| fun _ ->
128+
let value1 = ValueNone
129+
let f () = 42
130+
let add2 = (+) 2
131+
Expect.equal (ValueOption.either add2 f value1) 42 ""
132+
]
133+
117134
let allTests =
118135
testList "ValueOption Tests" [
119136
traverseResultTests
@@ -122,6 +139,7 @@ let allTests =
122139
ofResultTests
123140
ofNullTests
124141
bindNullTests
142+
eitherTests
125143
]
126144
#else
127145

0 commit comments

Comments
 (0)