diff --git a/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj b/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj
index f1da150b..fd8b9c47 100644
--- a/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj
+++ b/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj
@@ -21,8 +21,10 @@
-
+
+
+
diff --git a/src/FsToolkit.ErrorHandling.JobResult/JobOption.fs b/src/FsToolkit.ErrorHandling.JobResult/JobOption.fs
new file mode 100644
index 00000000..eaddde68
--- /dev/null
+++ b/src/FsToolkit.ErrorHandling.JobResult/JobOption.fs
@@ -0,0 +1,26 @@
+namespace FsToolkit.ErrorHandling
+
+open Hopac
+open Hopac.Infixes
+
+[]
+module JobOption =
+
+ let inline map f ar =
+ Job.map (Option.map f) ar
+
+ let bind f (ar: Job<_>) = job {
+ let! opt = ar
+ let t =
+ match opt with
+ | Some x -> f x
+ | None -> job { return None }
+ return! t
+ }
+
+ let retn x =
+ job { return Some x }
+
+ let apply f x =
+ bind (fun f' ->
+ bind (fun x' -> retn (f' x')) x) f
\ No newline at end of file
diff --git a/src/FsToolkit.ErrorHandling.JobResult/JobOptionOp.fs b/src/FsToolkit.ErrorHandling.JobResult/JobOptionOp.fs
new file mode 100644
index 00000000..3c6e9206
--- /dev/null
+++ b/src/FsToolkit.ErrorHandling.JobResult/JobOptionOp.fs
@@ -0,0 +1,10 @@
+namespace FsToolkit.ErrorHandling.Operator.JobOption
+
+open FsToolkit.ErrorHandling
+
+[]
+module JobOption =
+
+ let inline () f x = JobOption.map f x
+ let inline (<*>) f x = JobOption.apply f x
+ let inline (>>=) x f = JobOption.bind f x
\ No newline at end of file
diff --git a/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj b/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj
index dc0bfece..9c1d20a2 100644
--- a/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj
+++ b/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj
@@ -24,7 +24,9 @@
+
+
diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs b/src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs
new file mode 100644
index 00000000..a53f0d39
--- /dev/null
+++ b/src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs
@@ -0,0 +1,27 @@
+namespace FsToolkit.ErrorHandling
+
+open System.Threading.Tasks
+open FSharp.Control.Tasks.V2.ContextInsensitive
+
+[]
+module TaskOption =
+
+ let inline map f ar =
+ Task.map (Option.map f) ar
+
+ let bind f (ar: Task<_>) =
+ task {
+ let! opt = ar
+ let t =
+ match opt with
+ | Some x -> f x
+ | None -> task { return None }
+ return! t
+ }
+
+ let retn x =
+ task { return Some x }
+
+ let apply f x =
+ bind (fun f' ->
+ bind (fun x' -> retn (f' x')) x) f
\ No newline at end of file
diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskOptionOp.fs b/src/FsToolkit.ErrorHandling.TaskResult/TaskOptionOp.fs
new file mode 100644
index 00000000..0ccf846a
--- /dev/null
+++ b/src/FsToolkit.ErrorHandling.TaskResult/TaskOptionOp.fs
@@ -0,0 +1,10 @@
+namespace FsToolkit.ErrorHandling.Operator.TaskOption
+
+open FsToolkit.ErrorHandling
+
+[]
+module TaskOption =
+
+ let inline () f x = TaskOption.map f x
+ let inline (<*>) f x = TaskOption.apply f x
+ let inline (>>=) x f = TaskOption.bind f x
\ No newline at end of file
diff --git a/src/FsToolkit.ErrorHandling/AsyncOption.fs b/src/FsToolkit.ErrorHandling/AsyncOption.fs
new file mode 100644
index 00000000..cbbd9f25
--- /dev/null
+++ b/src/FsToolkit.ErrorHandling/AsyncOption.fs
@@ -0,0 +1,25 @@
+namespace FsToolkit.ErrorHandling
+
+open System.Threading.Tasks
+
+[]
+module AsyncOption =
+
+ let inline map f ar =
+ Async.map (Option.map f) ar
+
+ let bind f ar = async {
+ let! opt = ar
+ let t =
+ match opt with
+ | Some x -> f x
+ | None -> async { return None }
+ return! t
+ }
+
+ let retn x =
+ async { return Some x }
+
+ let apply f x =
+ bind (fun f' ->
+ bind (fun x' -> retn (f' x')) x) f
\ No newline at end of file
diff --git a/src/FsToolkit.ErrorHandling/AsyncOptionOp.fs b/src/FsToolkit.ErrorHandling/AsyncOptionOp.fs
new file mode 100644
index 00000000..53aa2489
--- /dev/null
+++ b/src/FsToolkit.ErrorHandling/AsyncOptionOp.fs
@@ -0,0 +1,10 @@
+namespace FsToolkit.ErrorHandling.Operator.AsyncOption
+
+open FsToolkit.ErrorHandling
+
+[]
+module AsyncOption =
+
+ let inline () f x = AsyncOption.map f x
+ let inline (<*>) f x = AsyncOption.apply f x
+ let inline (>>=) x f = AsyncOption.bind f x
\ No newline at end of file
diff --git a/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj b/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj
index fb78bba1..c1bf2410 100644
--- a/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj
+++ b/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj
@@ -37,7 +37,9 @@
+
+
diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/Expect.JobOption.fs b/tests/FsToolkit.ErrorHandling.JobResult.Tests/Expect.JobOption.fs
new file mode 100644
index 00000000..4801f19d
--- /dev/null
+++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/Expect.JobOption.fs
@@ -0,0 +1,21 @@
+namespace Expects.JobOption
+
+module Expect =
+ open Expecto
+ open Hopac
+
+ let hasJobValue v jobX =
+ let x = run jobX
+ if v = x then
+ ()
+ else Tests.failtestf "Expected %A, was %A." v x
+
+
+ let hasJobSomeValue v jobX =
+ let x = run jobX
+ TestHelpers.Expect.hasSomeValue v x
+
+
+ let hasJobNoneValue jobX =
+ let x = run jobX
+ TestHelpers.Expect.hasNoneValue x
diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj b/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj
index 78bb57cf..9b1485fc 100644
--- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj
+++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj
@@ -15,9 +15,11 @@
+
+
diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOption.fs b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOption.fs
new file mode 100644
index 00000000..22028581
--- /dev/null
+++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOption.fs
@@ -0,0 +1,100 @@
+module JobOptionTests
+
+
+open Expecto
+open Expects.JobOption
+open SampleDomain
+open TestData
+open TestHelpers
+open FsToolkit.ErrorHandling
+open FsToolkit.ErrorHandling.Operator.JobOption
+open System
+open Hopac
+
+let runJobSync = run
+let createPostSome = createPostSome >> Job.fromAsync
+let getFollowersSome = getFollowersSome >> Job.fromAsync
+let allowedToPostOptional = allowedToPostOptional >> Job.fromAsync
+
+let mapTests =
+ testList "JobOption.map Tests" [
+ testCase "map with Job(Some x)" <| fun _ ->
+ Job.singleton (Some validTweet)
+ |> JobOption.map remainingCharacters
+ |> Expect.hasJobSomeValue 267
+
+ testCase "map with Job(None)" <| fun _ ->
+ Job.singleton (None)
+ |> JobOption.map remainingCharacters
+ |> Expect.hasJobNoneValue
+ ]
+
+let bindTests =
+ testList "JobOption.bind tests" [
+ testCase "bind with Job(Some x)" <| fun _ ->
+ allowedToPostOptional sampleUserId
+ |> JobOption.bind (fun isAllowed -> job {
+ if isAllowed then
+ return! createPostSome validCreatePostRequest
+ else
+ return None })
+ |> Expect.hasJobSomeValue (PostId newPostId)
+
+ testCase "bind with Job(None)" <| fun _ ->
+ allowedToPostOptional (UserId (Guid.NewGuid()))
+ |> JobOption.bind (fun isAllowed -> job {return Some isAllowed})
+ |> Expect.hasJobNoneValue
+
+ testCase "bind with Job(Ok x) that returns Job (None)" <| fun _ ->
+ allowedToPostOptional sampleUserId
+ |> JobOption.bind (fun _ -> job {
+ return None
+ })
+ |> Expect.hasJobNoneValue
+ ]
+
+let applyTests =
+ testList "JobOption.apply Tests" [
+ testCase "apply with Job(Some x)" <| fun _ ->
+ Job.singleton (Some validTweet)
+ |> JobOption.apply (Job.singleton (Some remainingCharacters))
+ |> Expect.hasJobSomeValue (267)
+
+ testCase "apply with Job(None)" <| fun _ ->
+ Job.singleton None
+ |> JobOption.apply (Job.singleton (Some remainingCharacters))
+ |> Expect.hasJobNoneValue
+ ]
+
+let retnTests =
+ testList "JobOption.retn Tests" [
+ testCase "retn with x" <| fun _ ->
+ JobOption.retn 267
+ |> Expect.hasJobSomeValue (267)
+ ]
+
+let jobOptionOperatorTests =
+ testList "JobOption Operators Tests" [
+ testCase "map & apply operators" <| fun _ ->
+ let getFollowersResult = getFollowersSome sampleUserId
+ let createPostResult = createPostSome validCreatePostRequest
+ newPostRequest getFollowersResult <*> createPostResult
+ |> Expect.hasJobSomeValue {NewPostId = PostId newPostId; UserIds = followerIds}
+
+ testCase "bind operator" <| fun _ ->
+ allowedToPostOptional sampleUserId
+ >>= (fun isAllowed ->
+ if isAllowed then
+ createPostSome validCreatePostRequest
+ else
+ Job.singleton None)
+ |> Expect.hasJobSomeValue (PostId newPostId)
+ ]
+
+let allTests = testList "Job Option Tests" [
+ mapTests
+ bindTests
+ applyTests
+ retnTests
+ jobOptionOperatorTests
+]
\ No newline at end of file
diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj
index 3476f254..f8677278 100644
--- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj
+++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj
@@ -19,6 +19,7 @@
+
diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs
new file mode 100644
index 00000000..5e8cc33e
--- /dev/null
+++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs
@@ -0,0 +1,106 @@
+module TaskOptionTests
+
+
+#if FABLE_COMPILER
+open Fable.Mocha
+#else
+open Expecto
+#endif
+
+open System
+open System.Threading.Tasks
+open FSharp.Control.Tasks.V2.ContextInsensitive
+open TestData
+open TestHelpers
+open SampleDomain
+open FsToolkit.ErrorHandling
+open FsToolkit.ErrorHandling.Operator.TaskOption
+
+let runTaskSync (task : Task<_>) =
+ task.Result
+let createPostSome = createPostSome >> Async.StartAsTask
+let getFollowersSome = getFollowersSome >> Async.StartAsTask
+let allowedToPostOptional = allowedToPostOptional >> Async.StartAsTask
+
+let mapTests =
+ testList "TaskOption.map Tests" [
+ testCase"map with Task(Some x)" <| fun _ ->
+ Task.singleton (Some validTweet)
+ |> TaskOption.map remainingCharacters
+ |> Expect.hasTaskSomeValue 267
+
+ testCase "map with Task(None)" <| fun _ ->
+ Task.singleton (None)
+ |> TaskOption.map remainingCharacters
+ |> Expect.hasTaskNoneValue
+ ]
+
+let bindTests =
+ testList "TaskOption.bind tests" [
+ testCase "bind with Task(Some x)" <| fun _ ->
+ allowedToPostOptional sampleUserId
+ |> TaskOption.bind (fun isAllowed -> task {
+ if isAllowed then
+ return! createPostSome validCreatePostRequest
+ else
+ return None })
+ |> Expect.hasTaskSomeValue (PostId newPostId)
+
+ testCase "bind with Task(None)" <| fun _ ->
+ allowedToPostOptional (UserId (Guid.NewGuid()))
+ |> TaskOption.bind (fun isAllowed -> task {return Some isAllowed})
+ |> Expect.hasTaskNoneValue
+
+ testCase "bind with Task(Ok x) that returns Task (None)" <| fun _ ->
+ allowedToPostOptional sampleUserId
+ |> TaskOption.bind (fun _ -> task {
+ return None
+ })
+ |> Expect.hasTaskNoneValue
+ ]
+
+let applyTests =
+ testList "TaskOption.apply Tests" [
+ testCase "apply with Task(Some x)" <| fun _ ->
+ Task.singleton (Some validTweet)
+ |> TaskOption.apply (Task.singleton (Some remainingCharacters))
+ |> Expect.hasTaskSomeValue (267)
+
+ testCase "apply with Task(None)" <| fun _ ->
+ Task.singleton None
+ |> TaskOption.apply (Task.singleton (Some remainingCharacters))
+ |> Expect.hasTaskNoneValue
+ ]
+
+let retnTests =
+ testList "TaskOption.retn Tests" [
+ testCase "retn with x" <| fun _ ->
+ TaskOption.retn 267
+ |> Expect.hasTaskSomeValue (267)
+ ]
+
+let taskOptionOperatorTests =
+ testList "TaskOption Operators Tests" [
+ testCase "map & apply operators" <| fun _ ->
+ let getFollowersResult = getFollowersSome sampleUserId
+ let createPostResult = createPostSome validCreatePostRequest
+ newPostRequest getFollowersResult <*> createPostResult
+ |> Expect.hasTaskSomeValue {NewPostId = PostId newPostId; UserIds = followerIds}
+
+ testCase "bind operator" <| fun _ ->
+ allowedToPostOptional sampleUserId
+ >>= (fun isAllowed ->
+ if isAllowed then
+ createPostSome validCreatePostRequest
+ else
+ Task.singleton None)
+ |> Expect.hasTaskSomeValue (PostId newPostId)
+ ]
+
+let allTests = testList "Task Option Tests" [
+ mapTests
+ bindTests
+ applyTests
+ retnTests
+ taskOptionOperatorTests
+]
\ No newline at end of file
diff --git a/tests/FsToolkit.ErrorHandling.Tests/AsyncOption.fs b/tests/FsToolkit.ErrorHandling.Tests/AsyncOption.fs
new file mode 100644
index 00000000..7a2cefaf
--- /dev/null
+++ b/tests/FsToolkit.ErrorHandling.Tests/AsyncOption.fs
@@ -0,0 +1,102 @@
+module AsyncOptionTests
+
+
+#if FABLE_COMPILER
+open Fable.Mocha
+#else
+open Expecto
+#endif
+
+open System
+open TestData
+open TestHelpers
+open SampleDomain
+open FsToolkit.ErrorHandling
+open FsToolkit.ErrorHandling.Operator.AsyncOption
+
+let mapTests =
+ testList "AsyncOption.map Tests" [
+ testCaseAsync "map with Async(Some x)" <|
+ (Async.singleton (Some validTweet)
+ |> AsyncOption.map remainingCharacters
+ |> Expect.hasAsyncSomeValue 267)
+
+ testCaseAsync "map with Async(None)" <|
+ (Async.singleton (None)
+ |> AsyncOption.map remainingCharacters
+ |> Expect.hasAsyncNoneValue)
+ ]
+
+let bindTests =
+ testList "AsyncOption.bind tests" [
+ testCaseAsync "bind with Async(Some x)" <|
+ (allowedToPostOptional sampleUserId
+ |> AsyncOption.bind (fun isAllowed -> async {
+ if isAllowed then
+ return! createPostSome validCreatePostRequest
+ else
+ return None })
+ |> Expect.hasAsyncSomeValue (PostId newPostId))
+
+ testCaseAsync "bind with Async(None)" <|
+ (allowedToPostOptional (UserId (Guid.NewGuid()))
+ |> AsyncOption.bind (fun isAllowed -> async {return Some isAllowed})
+ |> Expect.hasAsyncNoneValue )
+
+ testCaseAsync "bind with Async(Ok x) that returns Async (None)" <|
+ (allowedToPostOptional sampleUserId
+ |> AsyncOption.bind (fun _ -> async {
+ return None
+ })
+ |> Expect.hasAsyncNoneValue)
+ ]
+
+let applyTests =
+ testList "AsyncOption.apply Tests" [
+ testCaseAsync "apply with Async(Some x)" <| (
+ Async.singleton (Some validTweet)
+ |> AsyncOption.apply (Async.singleton (Some remainingCharacters))
+ |> Expect.hasAsyncSomeValue (267))
+
+ testCaseAsync "apply with Async(None)" <| (
+ Async.singleton None
+ |> AsyncOption.apply (Async.singleton (Some remainingCharacters))
+ |> Expect.hasAsyncNoneValue)
+ ]
+
+let retnTests =
+ testList "AsyncOption.retn Tests" [
+ testCaseAsync "retn with x" <| (
+ AsyncOption.retn 267
+ |> Expect.hasAsyncSomeValue (267))
+ ]
+
+let asyncOptionOperatorTests =
+ testList "AsyncOption Operators Tests" [
+ testCaseAsync "map & apply operators" <| async {
+ let getFollowersResult = getFollowersSome sampleUserId
+ let createPostResult = createPostSome validCreatePostRequest
+ do!
+ newPostRequest getFollowersResult <*> createPostResult
+ |> Expect.hasAsyncSomeValue {NewPostId = PostId newPostId; UserIds = followerIds}
+ }
+
+ testCaseAsync "bind operator" <| async {
+ do!
+ allowedToPostOptional sampleUserId
+ >>= (fun isAllowed ->
+ if isAllowed then
+ createPostSome validCreatePostRequest
+ else
+ Async.singleton None)
+ |> Expect.hasAsyncSomeValue (PostId newPostId)
+ }
+ ]
+
+let allTests = testList "Async Option Tests" [
+ mapTests
+ bindTests
+ applyTests
+ retnTests
+ asyncOptionOperatorTests
+]
\ No newline at end of file
diff --git a/tests/FsToolkit.ErrorHandling.Tests/Expect.fs b/tests/FsToolkit.ErrorHandling.Tests/Expect.fs
index 14787c73..b234af5b 100644
--- a/tests/FsToolkit.ErrorHandling.Tests/Expect.fs
+++ b/tests/FsToolkit.ErrorHandling.Tests/Expect.fs
@@ -37,6 +37,20 @@ module Expect =
| Error x ->
Tests.failtestf "Expected Ok, was Error(%A)." x
+ let hasSomeValue v x =
+ match x with
+ | Some x when x = v -> ()
+ | Some x ->
+ Tests.failtestf "Expected Some(%A), was Some(%A)." v x
+ | None ->
+ Tests.failtestf "Expected Some, was None."
+
+ let hasNoneValue x =
+ match x with
+ | None -> ()
+ | Some _ ->
+ Tests.failtestf "Expected None, was Some."
+
let hasAsyncValue v asyncX = async {
let! x = asyncX
if v = x then
@@ -69,6 +83,24 @@ module Expect =
let x = taskX |> Async.AwaitTask |> Async.RunSynchronously
hasErrorValue v x
+ let hasAsyncSomeValue v asyncX = async {
+ let! x = asyncX
+ hasSomeValue v x
+ }
+
+ let hasTaskSomeValue v taskX =
+ let x = taskX |> Async.AwaitTask |> Async.RunSynchronously
+ hasSomeValue v x
+
+ let hasAsyncNoneValue asyncX = async {
+ let! x = asyncX
+ hasNoneValue x
+ }
+
+ let hasTaskNoneValue taskX =
+ let x = taskX |> Async.AwaitTask |> Async.RunSynchronously
+ hasNoneValue x
+
let same expected actual =
Expect.equal actual expected "expected and actual should be same"
diff --git a/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj b/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj
index e6ce20ab..479247f4 100644
--- a/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj
+++ b/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj
@@ -20,6 +20,7 @@
+
diff --git a/tests/FsToolkit.ErrorHandling.Tests/Main.fs b/tests/FsToolkit.ErrorHandling.Tests/Main.fs
index beed3769..1227c0e4 100644
--- a/tests/FsToolkit.ErrorHandling.Tests/Main.fs
+++ b/tests/FsToolkit.ErrorHandling.Tests/Main.fs
@@ -12,6 +12,7 @@ let allTests = testList "All Tests" [
ResultOptionTests.allTests
OptionTests.allTests
OptionCETests.allTests
+ AsyncOptionTests.allTests
AsyncOptionCETests.allTests
ListTests.allTests
AsyncResultTests.allTests
diff --git a/tests/FsToolkit.ErrorHandling.Tests/SampleDomain.fs b/tests/FsToolkit.ErrorHandling.Tests/SampleDomain.fs
index c394fd82..975cb147 100644
--- a/tests/FsToolkit.ErrorHandling.Tests/SampleDomain.fs
+++ b/tests/FsToolkit.ErrorHandling.Tests/SampleDomain.fs
@@ -175,6 +175,13 @@ let allowedToPost userId = async {
return Error commonEx
}
+let allowedToPostOptional userId = async {
+ if (userId = sampleUserId) then
+ return Some true
+ else
+ return None
+}
+
let newPostId = Guid.NewGuid()
type PostId = PostId of Guid
@@ -194,13 +201,19 @@ let createPostSuccess (_ : CreatePostRequest) = async {
return Ok samplePostId
}
+let createPostSome (_ : CreatePostRequest) = async {
+ return Some samplePostId
+}
+
let followerIds = [UserId (Guid.NewGuid()); UserId (Guid.NewGuid())]
let getFollowersSuccess (UserId _) = async {
return Ok followerIds
}
-
+let getFollowersSome (UserId _) = async {
+ return Some followerIds
+}
let getFollowersFailure (UserId _) = async {
return Error getFollowersEx