### requireHead Example (Success) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Demonstrates requireHead to get the first element of a sequence. Returns Ok with the head if the sequence is not empty. ```fsharp let result : Result = [1; 2; 3] |> Result.requireHead "Seq must have head" // Ok 1 ``` -------------------------------- ### Example 1: Validating User and Permissions Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskValidation/bind.md This example demonstrates using `bind` to sequentially validate if a user exists before validating their role. The process short-circuits if `fetchUser` fails. ```APIDOC ### Example 1 Sequentially validating a user exists before validating their permissions: ```fsharp let validateUserWithPermissions (userId: UserId) : CancellableTaskValidation = fetchUser userId |> CancellableTaskValidation.bind (fun user -> fetchAndValidateRole user) ``` ``` -------------------------------- ### Example 2: Chaining Payment Processing Steps Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskValidation/bind.md This example shows how `bind` can be used to chain multiple validation and processing steps in a payment pipeline. Each step depends on the success of the previous one. ```APIDOC ### Example 2 Chaining validation steps in a pipeline: ```fsharp let processPayment (request: PaymentRequest) : CancellableTaskValidation = validatePaymentRequest request |> CancellableTaskValidation.bind authorizePayment |> CancellableTaskValidation.bind chargeCard ``` ``` -------------------------------- ### Example Usage of validateCreatePostRequest Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/tryCreate.md Shows example calls to validateCreatePostRequest with both valid and invalid optional location data, demonstrating error reporting. ```fsharp validateCreatePostRequest {Tweet = ""; Location = Some {Latitude = 300.; Longitude = 400.}} // Error // [("latitude", "300.0 is a invalid latitude value") // ("longitude", "400.0 is a invalid longitude value") // ("tweet", "Tweet shouldn't be empty")] validateCreatePostRequest {Tweet = ""; Location = None} // Error [("tweet", "Tweet shouldn't be empty")] ``` -------------------------------- ### Example 1: Successful Binding Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskOption/bind.md This example demonstrates a successful binding where the initial task contains a value that is found by the lookup function. ```APIDOC ### Example 1 ```fsharp let taskOpt : CancellableTask = CancellableTaskOption.some "john@test.com" // CancellableTask |> CancellableTaskOption.bind lookupAccountByEmail // CancellableTask // cancellableTask { Some { EmailAddress = "john@test.com"; Name = "John Johnson" } } ``` ``` -------------------------------- ### Example 3: Binding with Initial None Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskOption/bind.md This example illustrates binding when the initial task already contains None, resulting in a final task that also contains None. ```APIDOC ### Example 3 ```fsharp let taskOpt : CancellableTask = CancellableTask.singleton None // CancellableTask |> CancellableTaskOption.bind lookupAccountByEmail // CancellableTask // cancellableTask { None } ``` ``` -------------------------------- ### requireHead Example (Error) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Shows requireHead resulting in an error when the sequence is empty. ```fsharp let result : Result = [] |> Result.requireHead "Seq must have head" // Error "Seq must have head" ``` -------------------------------- ### requireEqualTo Example (Success) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Shows requireEqualTo used with piping for a successful equality check. ```fsharp let result : Result = 1 |> Result.requireEqualTo "Value must be equal to 1" 1 // Ok () ``` -------------------------------- ### Concurrent Task Execution with Error Handling Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskResult/parallelZip.md Demonstrates `parallelZip` where both tasks start simultaneously. Unlike `zip`, neither task is skipped if the other returns an error first. The example shows validating credentials by looking up user and role concurrently. ```fsharp let validateCredentials (username: string) (password: string) : CancellableTaskResult = CancellableTaskResult.parallelZip (lookupUser username) // both run concurrently (lookupRole username) // both run concurrently; short-circuits on first Error ``` -------------------------------- ### requireEqualTo Example (Error) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Illustrates requireEqualTo with piping, resulting in an error when values are not equal. ```fsharp let result : Result = 2 |> Result.requireEqualTo "Value must be equal to 1" 1 // Error "Value must be equal to 1" ``` -------------------------------- ### require Example (Success) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Illustrates the require function for Result types, where the predicate on the Ok value returns true. ```fsharp let result: Result = Result.Ok "F#" |> Result.require (_.Contains("#")) "Provided input does not contain #" // Ok "F#" ``` -------------------------------- ### Example 2: Binding with No Result Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskOption/bind.md This example shows a case where the initial task contains a value, but the lookup function does not find a corresponding result. ```APIDOC ### Example 2 ```fsharp let taskOpt : CancellableTask = CancellableTaskOption.some "jerry@test.com" // CancellableTask |> CancellableTaskOption.bind lookupAccountByEmail // CancellableTask // cancellableTask { None } ``` ``` -------------------------------- ### requireEmpty Example (Success) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Demonstrates requireEmpty to check if a sequence is empty. Returns Ok if it is. ```fsharp let result : Result = [] |> Result.requireEmpty "Value must be empty" // Ok () ``` -------------------------------- ### Option.sequenceTaskResult Examples Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/sequenceTaskResult.md Demonstrates the usage of Option.sequenceTaskResult with different scenarios, including successful results, error results, and None values. ```fsharp let r1 : Task> = Some (task { return Ok 42 }) |> Option.sequenceTaskResult // task { return Ok (Some 42) } ``` ```fsharp let r2 : Task> = Some (task { return Error "something went wrong" }) |> Option.sequenceTaskResult // task { return Error "something went wrong" } ``` ```fsharp let r3 : Task> = None |> Option.sequenceTaskResult // task { return Ok None } ``` -------------------------------- ### Example 1: Successful Binding Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskOption/bind.md Demonstrates using CancellableValueTaskOption.bind with a value that exists, resulting in a CancellableValueTask containing the looked-up account. ```APIDOC ## Example 1: Successful Binding ### Description This example shows a successful binding where the input email exists in the lookup function. ### Code ```fsharp let taskOpt : CancellableValueTask = CancellableValueTaskOption.some "john@test.com" // CancellableValueTask |> CancellableValueTaskOption.bind lookupAccountByEmail // CancellableValueTask // Expected result: cancellableValueTask { Some { EmailAddress = "john@test.com"; Name = "John Johnson" } } ``` ``` -------------------------------- ### SequenceResult Examples Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/sequenceResult.md Demonstrates the behavior of Option.sequenceResult with different inputs, including a successful Result, a failed Result, and None. ```fsharp let r1 : Result = Option.sequenceResult (Some (Ok 42)) // Ok (Some 42) ``` ```fsharp let r2 : Result = Option.sequenceResult (Some (Error "something went wrong")) // Error "something went wrong" ``` ```fsharp let r3 : Result = Option.sequenceResult None // Ok None ``` -------------------------------- ### Define Helper Functions Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskOption/ce.md These are helper functions used in the example. Ensure these functions are defined and accessible. ```fsharp tryParseInt : string -> int option tryFindPersonById : int -> CancellableValueTask updatePerson : Person -> CancellableValueTask ``` -------------------------------- ### Define Helper Functions for JobOption Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/jobOption/ce.md These are type signatures for helper functions used in the JobOption computation expression example. They define functions for parsing integers, finding a person by ID, and updating a person. ```fsharp tryParseInt : string -> int option tryFindPersonById : int -> Job updatePerson : Person -> Job ``` -------------------------------- ### CancellableTask.map3 Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskValidation/map3.md Demonstrates how to use CancellableTask.map3 to combine three cancellable tasks. Errors from any task are collected into a list. ```fsharp let task1 = CancellableTask.FromResult(Result.Ok(1)) let task2 = CancellableTask.FromResult(Result.Ok(2)) let task3 = CancellableTask.FromResult(Result.Ok(3)) let mappedTask = CancellableTask.map3 ( fun a b c -> a + b + c ) task1 task2 task3 // mappedTask will be CancellableTask> ``` -------------------------------- ### requireEmpty Example (Error) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Shows requireEmpty resulting in an error when the sequence is not empty. ```fsharp let result : Result = [1] |> Result.requireEmpty "Value must be empty" // Error "Value must be empty" ``` -------------------------------- ### requireNotEmpty Example (Error) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Shows requireNotEmpty resulting in an error when the sequence is empty. ```fsharp let result : Result = [] |> Result.requireNotEmpty "Value must not be empty" // Error "Value must not be empty" ``` -------------------------------- ### Option.sequenceAsyncResult Examples Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/sequenceAsyncResult.md Demonstrates the usage of Option.sequenceAsyncResult with different scenarios: a successful asynchronous operation, a failing asynchronous operation, and a None value. ```fsharp let r1 : Async> = Some (async { return Ok 42 }) |> Option.sequenceAsyncResult // async { return Ok (Some 42) } ``` ```fsharp let r2 : Async> = Some (async { return Error "something went wrong" }) |> Option.sequenceAsyncResult // async { return Error "something went wrong" } ``` ```fsharp let r3 : Async> = None |> Option.sequenceAsyncResult // async { return Ok None } ``` -------------------------------- ### Partition Results After Mapping Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/array/partitionResults.md This example demonstrates partitioning an array of Results that were generated by mapping a function over an array of strings. It shows how to handle potential errors during parsing. ```fsharp // string -> Result let tryParseInt str = match System.Int32.TryParse str with | true, x -> Ok x | false, _ -> Error (sprintf "unable to parse '%s' to integer" str) [| "1"; "foo"; "3"; "bar" |] |> Array.map tryParseInt |> Array.partitionResults // ([| 1; 3 |], [| "unable to parse 'foo' to integer"; "unable to parse 'bar' to integer" |]) ``` -------------------------------- ### Define helper functions for Result.map2 example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/map2.md Defines an 'add' function and a 'tryParseInt' function for demonstrating Result.map2. ```fsharp let add a b = a + b ``` ```fsharp let tryParseInt (str: string) = match System.Int32.TryParse str with | true, x -> Ok x | false, _ -> Error (sprintf "unable to parse '%s' to integer" str) ``` -------------------------------- ### requireNotEmpty Example (Success) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Illustrates requireNotEmpty to check if a sequence is not empty. Returns Ok if it is not. ```fsharp let result : Result = [1] |> Result.requireNotEmpty "Value must not be empty" // Ok () ``` -------------------------------- ### FsToolkit.ErrorHandling.map2 Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/validation/map2.md Demonstrates how map2 combines two successful results. If either result is an error, all errors are collected. ```fsharp let add x y = x + y let res1 = Ok(1) let res2 = Ok(2) let mapped = FsToolkit.ErrorHandling.map2 add res1 res2 // mapped = Ok(3) let err1 = Error(["Error A"]) let err2 = Error(["Error B"]) let mappedErr = FsToolkit.ErrorHandling.map2 add res1 err2 // mappedErr = Error(["Error B"]) let mappedErrs = FsToolkit.ErrorHandling.map2 add err1 err2 // mappedErrs = Error(["Error A", "Error B"]) ``` -------------------------------- ### AsyncResultOption Map2 Operator Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/asyncResultOption/operators.md Demonstrates using the map2 operator () with AsyncResultOption. Ensure the FsToolkit.ErrorHandling.Operator.AsyncResult namespace is open. ```fsharp open FsToolkit.ErrorHandling.Operator.Async // Async> userTweet (getPostById samplePostId) <*> (getUserById sampleUserId) ``` -------------------------------- ### requireEqual Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Demonstrates the use of requireEqual to check if two values are equal. Returns an error if they are not. ```fsharp let result : Result = Result.requireEqual 1 2 "Value must be equal to 1" // Error "Value must be equal to 1" ``` -------------------------------- ### require Example (Error) Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/requireFunctions.md Shows the require function for Result types, where the predicate on the Ok value returns false, resulting in an error. ```fsharp let result: Result = Result.Ok "Hello World!" |> Result.require (_.Contains("#")) "Provided input does not contain #" // Error "Provided input does not contain #" ``` -------------------------------- ### Handle Some case with TaskOption.either Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskOption/either.md When the input is Some, the first function is executed. Ensure the onSome function returns a Task. This example shows handling a Some value. ```fsharp TaskOption.either (fun x -> task { x * 2 }) (task { 0 }) (TaskOption.some 5) // task { 10 } ``` -------------------------------- ### Define helper functions Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/eitherFunctions.md These are helper functions used in the examples. `okF` increments an integer, and `errorF` decrements it. ```fsharp // int -> int let okF (x : int) = x + 1 // int -> int let errorF (x : int) = x - 1 ``` -------------------------------- ### Execute function for Some value with Option.either Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/either.md When the option is Some, the first function is executed with the unwrapped value. This example demonstrates doubling the value. ```fsharp Option.either (fun x -> x * 2) (fun () -> 0) (Some 5) // 10 ``` -------------------------------- ### Example Usage of AsyncResult.map2 Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/asyncResult/map2.md Demonstrates how to use AsyncResult.map2 to combine the results of two asynchronous operations, `getFollowerIds` and `createPost`, to construct a `NotifyNewPostRequest`. ```APIDOC ### Example 1 Given the functions ```fsharp getFollowerIds : UserId -> Async> createPost : CreatePostRequest -> Async> ``` And the type ```fsharp type NotifyNewPostRequest = { UserIds : UserId list NewPostId : PostId } static member Create userIds newPostsId = {UserIds = userIds; NewPostId = newPostsId} ``` We can create a `NotifyNewPostRequest` using `AsyncResult.map2` as below: ```fsharp let createPostAndGetNotifyRequest (req : CreatePostRequest) = // Async> let getFollowersResult = getFollowerIds req.UserId // Async> let createPostResult = createPost req // Async> let newPostRequestResult = AsyncResult.map2 NotifyNewPostRequest.Create getFollowersResult createPostResult // ... ``` ``` -------------------------------- ### Map2 with Infix Operators Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/resultOption/operators.md Rewrites a Map2 example using infix operators for combining Result and Option values. ```fsharp let toCreatePostRequest (dto : CreatePostRequestDto) = // Result let locationR = location Option.traverseResult Latitude.TryCreate dto.Latitude <*> Option.traverseResult Longitude.TryCreate dto.Longitude // Result let tweetR = Tweet.TryCreate dto.Tweet // Result Result.map2 createPostRequest tweetR locationR ``` -------------------------------- ### Parallel Async Validation CE Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/parallelAsyncValidation/ce.md Demonstrates the usage of the parallelAsyncValidation CE with successful results. Workflows are executed concurrently. ```fsharp // Result -> Async> let downloadAsync stuff = async { return stuff } // AsyncValidation let addResult = parallelAsyncValidation { let! x = downloadAsync (Ok "I") and! y = downloadAsync (Ok "am") and! z = downloadAsync (Ok "concurrent!") return sprintf "%s %s %s" x y z } // async { return Ok "I am concurrent!" } ``` -------------------------------- ### Execute task based on ValueSome Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskValueOption/either.md When the input is a ValueSome, the first function is executed. This example doubles the value inside the Task. ```fsharp TaskValueOption.either (fun x -> task { x * 2 }) (task { 0 }) (TaskValueOption.valueSome 5) // task { 10 } ``` -------------------------------- ### Example 3: Binding with None Input Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskOption/bind.md Shows the behavior of CancellableValueTaskOption.bind when the input CancellableValueTask is already None, resulting in a CancellableValueTask containing None. ```APIDOC ## Example 3: Binding with None Input ### Description This example illustrates the behavior when the input CancellableValueTask is already None. ### Code ```fsharp let taskOpt : CancellableValueTask = CancellableValueTask.singleton None // CancellableValueTask |> CancellableValueTaskOption.bind lookupAccountByEmail // CancellableValueTask // Expected result: cancellableValueTask { None } ``` ``` -------------------------------- ### Sequence TaskResultM Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/list/sequenceTaskResultM.md Demonstrates how to use `sequenceTaskResultM` to process a list of tasks that return results. This is useful when you have multiple operations that might fail and you want to collect their successful results or stop at the first failure. ```fsharp let task1 = Task.FromResult(Result.Ok(1)) let task2 = Task.FromResult(Result.Ok(2)) let task3 = Task.FromResult(Result.Error("Failed")) let tasks = [task1; task2; task3] // This will result in Task.FromResult(Result.Error("Failed")) let sequencedTasks = List.sequenceTaskResultM tasks let task4 = Task.FromResult(Result.Ok(4)) let task5 = Task.FromResult(Result.Ok(5)) let successfulTasks = [task4; task5] // This will result in Task.FromResult(Result.Ok([4; 5])) let sequencedSuccessfulTasks = List.sequenceTaskResultM successfulTasks ``` -------------------------------- ### Handle ValueSome with ValueTaskValueOption.either Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/valueTaskValueOption/either.md This example demonstrates executing the `onValueSome` function when the input is `ValueSome`. The `onValueSome` function doubles the value and returns it within a ValueTask. ```fsharp ValueTaskValueOption.either (fun x -> valueTask { return x * 2 }) (fun () -> valueTask { return 0 }) (ValueTaskValueOption.valueSome 5) // valueTask { 10 } ``` -------------------------------- ### Chaining Async Operations with bind Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/asyncResultOption/bind.md Use bind to chain asynchronous functions that return an Async>. This example retrieves a post and then its associated user. ```fsharp // Async> getPostById postId |> AsyncResultOption.bind (fun post -> getUserById post.UserId) ``` -------------------------------- ### Example 2: Binding with Non-existent Value Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskOption/bind.md Illustrates using CancellableValueTaskOption.bind when the input value does not yield a result, leading to a CancellableValueTask containing None. ```APIDOC ## Example 2: Binding with Non-existent Value ### Description This example demonstrates binding with an input email that does not exist in the lookup function, resulting in None. ### Code ```fsharp let taskOpt : CancellableValueTask = CancellableValueTaskOption.some "jerry@test.com" // CancellableValueTask |> CancellableValueTaskOption.bind lookupAccountByEmail // CancellableValueTask // Expected result: cancellableValueTask { None } ``` ``` -------------------------------- ### Chaining configuration and data loading jobs Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/jobResultOption/bind.md This example demonstrates chaining two asynchronous operations: first finding a configuration, then loading data based on that configuration. Both operations return a Job>, making bind suitable for sequential execution. ```fsharp tryFindConfig : string -> Job> tryLoadData : Config -> Job> // Job> tryFindConfig "app.json" |> JobResultOption.bind tryLoadData ``` -------------------------------- ### Get value when key exists Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/tryGetValue.md Demonstrates using Option.tryGetValue to retrieve an existing value from a dictionary. The result is Some with the associated value. ```fsharp open System.Collections.Generic let dict = Dictionary() dict["apples"] <- 5 dict["bananas"] <- 3 let result : int option = dict |> Option.tryGetValue "apples" // Some 5 ``` -------------------------------- ### Apply function to three Some options Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/map3.md Use Option.map3 when all three input options are expected to contain values. This example demonstrates a successful transformation where all inputs are Some. ```fsharp Option.map3 (fun x y z -> x + y + z) (Some 1) (Some 2) (Some 3) // Some 6 ``` -------------------------------- ### Basic Task Creation Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskValidation/ce.md Demonstrates creating a basic Task that returns a value. ```fsharp // Result -> Task> let downloadTask stuff = task { return stuff } ``` -------------------------------- ### Notify Followers using Task.bindV Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/task/bindV.md This example demonstrates how to use Task.bindV to process a NotifyNewPostRequest wrapped in a ValueTask and then notify followers. Ensure notifyFollowers function is defined and newPostRequestResult is of type ValueTask. ```fsharp newPostRequestResult |> Task.bindV notifyFollowers ``` -------------------------------- ### Apply function to two Some options Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/map2.md Use Option.map2 when you have two optional values and want to apply a function to both if they exist. This example shows a successful application where both inputs are Some. ```fsharp Option.map2 (fun x y -> x + y) (Some 1) (Some 2) // Some 3 ``` -------------------------------- ### Define Account type and lookup function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskValueOption/bind.md Defines a sample Account type and a function to look up accounts by email, returning a Task. This is used in subsequent examples. ```fsharp type Account = { EmailAddress : string Name : string } // string -> Task let lookupAccountByEmail email = task { let john = { EmailAddress = "john@test.com"; Name = "John Johnson" } let jeff = { EmailAddress = "jeff@test.com"; Name = "Jeff Jefferson" } let jack = { EmailAddress = "jack@test.com"; Name = "Jack Jackson" } // Just a map lookup, but imagine we look up an account in our database let accounts = Map.ofList [ ("john@test.com", john) ("jeff@test.com", jeff) ("jack@test.com", jack) ] return accounts |> Map.tryFind email |> Option.toValueOption ``` -------------------------------- ### Fetch Two Independent Resources in Parallel Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskResult/parallelZip.md Use `parallelZip` to fetch two independent resources concurrently. This example demonstrates fetching user data and their permissions. ```fsharp let getUserAndPermissions (userId: UserId) : CancellableTaskResult = CancellableTaskResult.parallelZip (fetchUser userId) (fetchPermissions userId) ``` -------------------------------- ### TaskResultOption CE with TaskResultOption Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskResultOption/ce.md Illustrates chaining operations using the TaskResultOption computation expression, similar to the map2 example. Requires importing necessary functions like getPostById, getUserById, and userTweet. ```fsharp // Task> taskResultOption { let! post = getPostById samplePostId let! user = getUserById post.UserId return userTweet post user } ``` -------------------------------- ### Example 3: Implicit Bind in Computation Expression Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskValidation/bind.md This example illustrates how `bind` is implicitly used within a `cancellableTaskValidation` computation expression for sequential operations. If `validateEmail` fails, the subsequent `createUserRecord` call is skipped. ```APIDOC ### Example 3 Using `bind` inside a `cancellableTaskValidation` CE with sequential steps: ```fsharp let createUser (input: CreateUserInput) : CancellableTaskValidation = cancellableTaskValidation { let! validatedEmail = validateEmail input.Email // bind is used implicitly here — short-circuits if validateEmail fails let! userId = createUserRecord validatedEmail input.Name return userId } ``` ``` -------------------------------- ### Partition a list of Results Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/list/partitionResults.md Demonstrates basic usage of List.partitionResults with a mixed list of Ok and Error values. ```fsharp let results = [Ok 1; Error "bad"; Ok 2; Ok 3; Error "worse"] results |> List.partitionResults // ([1; 2; 3], ["bad"; "worse"]) ``` -------------------------------- ### CancellableTaskResult.parallelZip Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskResult/parallelZip.md Takes two CancellableTaskResult values, starts them concurrently, and returns a tuple of the results once both complete. If either computation returns an Error, that error is returned. Unlike zip, both computations are started before waiting for either to complete. ```APIDOC ## CancellableTaskResult.parallelZip ### Description Combines two `CancellableTaskResult` computations by running them concurrently. It returns a tuple containing the results of both computations once they have both successfully completed. If either of the input computations results in an error, that error is immediately returned, and the other computation may be cancelled. ### Signature ```fsharp CancellableTaskResult<'left, 'Error> -> CancellableTaskResult<'right, 'Error> -> CancellableTaskResult<'left * 'right, 'Error> ``` ### Parameters - `task1` (CancellableTaskResult<'left, 'Error>): The first cancellable task. - `task2` (CancellableTaskResult<'right, 'Error>): The second cancellable task. ### Returns - `CancellableTaskResult<'left * 'right, 'Error>`: A new `CancellableTaskResult` that yields a tuple of the results from `task1` and `task2` upon successful completion, or an error if either task fails. ### Examples #### Example 1: Fetching two independent resources in parallel ```fsharp let getUserAndPermissions (userId: UserId) : CancellableTaskResult = CancellableTaskResult.parallelZip (fetchUser userId) (fetchPermissions userId) ``` #### Example 2: Combining two concurrent API calls in a larger computation ```fsharp let loadDashboard (userId: UserId) : CancellableTaskResult = cancellableTaskResult { let! user, settings = CancellableTaskResult.parallelZip (fetchUser userId) (fetchUserSettings userId) return buildDashboard user settings } ``` #### Example 3: Error handling with parallel execution ```fsharp let validateCredentials (username: string) (password: string) : CancellableTaskResult = CancellableTaskResult.parallelZip (lookupUser username) // both run concurrently (lookupRole username) // both run concurrently; short-circuits on first Error ``` ``` -------------------------------- ### Get Default Value with Function from TaskOption Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskValueOption/others.md Use defaultWith to retrieve the contained value from a Task<'a voption> if it's ValueSome, otherwise evaluate a provided function to get the default result. This is useful when the default value needs to be computed. ```fsharp (unit -> 'a) -> Task<'a voption> -> Task<'a> ``` -------------------------------- ### Login Flow with CancellableValueTaskResult CE Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskResult/ce.md Implement a login flow using the `cancellableValueTaskResult` computation expression. This example demonstrates chaining asynchronous operations and handling various error types. ```fsharp tryGetUser : string -> CancellableValueTask isPwdValid : string -> User -> bool authorize : User -> CancellableValueTask> createAuthToken : User -> Result ``` ```fsharp type LoginError = | InvalidUser | InvalidPwd | Unauthorized of AuthError | TokenErr of TokenError let login (username: string) (password: string) : CancellableValueTask> = cancellableValueTaskResult { let! user = username |> tryGetUser |> CancellableValueTaskResult.requireSome InvalidUser do! user |> isPwdValid password |> Result.requireTrue InvalidPwd do! user |> authorize |> CancellableValueTaskResult.mapError Unauthorized return! user |> createAuthToken |> Result.mapError TokenErr } ``` -------------------------------- ### Import Lines from Stream using AsyncSeq in asyncResult Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/asyncSeq/ce.md This example demonstrates reading lines from a stream as an AsyncSeq and then processing each line within an asyncResult block. It shows how to create an AsyncSeq from a stream reader and use it in conjunction with other asyncResult operations. ```fsharp open FsToolkit.ErrorHandling open FSharp.Control let importLines (stream: System.IO.Stream) : Async> = asyncResult { let lines = asyncSeq { use reader = new System.IO.StreamReader(stream) while not reader.EndOfStream do yield reader.ReadLine() } for line in lines do do! persistLine line // persistLine : string -> Async> } ``` -------------------------------- ### Define a simple function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskOption/apply.md This is a helper function used in the examples to count the characters in a string. ```fsharp let characterCount (s: string) = s.Length ``` -------------------------------- ### Define Add Function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/resultOption/operators.md Defines a simple integer addition function used in subsequent examples. ```fsharp // int -> int -> int -> int let add a b c = a + b + c ``` -------------------------------- ### Sequential Asynchronous Workflow Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/parallelAsyncResult/ce.md Demonstrates downloading multiple files sequentially using the ayncResult computation expression. This workflow takes significantly longer due to its sequential nature. ```fsharp let downloadAllSequential = ayncResult { let! x = downloadAsync (Ok "We") let! y = downloadAsync (Ok "run") let! z = downloadAsync (Ok "sequentially :(") return sprintf "%s %s %s" x y z } ``` -------------------------------- ### Lift a value into AsyncResult.ok Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/asyncResult/ok.md Demonstrates how to use AsyncResult.ok to wrap a simple integer value into an asynchronous result. This is useful for creating a base case or a default successful outcome. ```fsharp let result : Async> = AsyncResult.ok 42 ``` -------------------------------- ### F# Login Flow with Error Handling Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/README.md Demonstrates composing a login flow using FsToolkit's computation expressions and helper functions for clear and powerful error handling. Requires helper functions like tryGetUser, isPwdValid, authorize, and createAuthToken. ```fsharp // Given the following functions: // tryGetUser: string -> Async // isPwdValid: string -> User -> bool // authorize: User -> Async> // createAuthToken: User -> Result type LoginError = InvalidUser | InvalidPwd | Unauthorized of AuthError | TokenErr of TokenError let login (username: string) (password: string) : Async> = asyncResult { // requireSome unwraps a Some value or gives the specified error if None let! user = username |> tryGetUser |> AsyncResult.requireSome InvalidUser // requireTrue gives the specified error if false do! user |> isPwdValid password |> Result.requireTrue InvalidPwd // Error value is wrapped/transformed (Unauthorized has signature AuthError -> LoginError) do! user |> authorize |> AsyncResult.mapError Unauthorized // Same as above, but synchronous, so we use the built-in mapError return! user |> createAuthToken |> Result.mapError TokenErr } ``` -------------------------------- ### Combine two singleton jobs Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/job/zip.md Demonstrates zipping two simple jobs that return a number and a string respectively. The resulting job will produce a tuple of these values. ```fsharp let left = Job.singleton 123 let right = Job.singleton "abc" Job.zip left right // job { return (123, "abc") } ``` -------------------------------- ### Ignore string value in Some option Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/ignore.md This example demonstrates ignoring a string value within a Some option, resulting in Some(()). ```fsharp let result : unit option = Some "hello" |> Option.ignore // Some () ``` -------------------------------- ### Convert Some to ValueOption Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/toValueOption.md Demonstrates converting a 'Some' value to a 'ValueOption'. The output will be 'Some 1'. ```fsharp let opt = Option.toValueOption (Some 1) // Some 1 ``` -------------------------------- ### defaultWith Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/others.md Returns the contained Ok value or evaluates a function to get a default value if the Result is an Error. ```APIDOC ## defaultWith ### Description Returns the contained value if Ok, otherwise evaluates the given function and returns the result. ### Function Signature ```fsharp (unit -> 'a) -> Result<'a, 'b> -> 'a ``` ``` -------------------------------- ### Apply Infix Operators with Option Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/resultOption/operators.md Demonstrates the use of map, apply, and bind infix operators with Option-wrapped values. ```fsharp // Ok (Some 42) let opResult : Result = add (Ok (Some 30)) <*> (Ok (Some 10)) <*> (Ok (Some 2)) ``` -------------------------------- ### Example 1: Converting Result to Choice Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/fold.md Demonstrates how Result.fold can be used to convert a Result type into a Choice type. ```APIDOC ## Example 1: Converting Result to Choice ### Description `fold` can be used to convert `Result` to another similar type, such as `Choice`: ### Code ```fsharp let choice1 = Ok 42 |> Result.fold Choice1Of2 Choice2Of2 // choice1 will be Choice1Of2 42 let choice2 = Error "An error occurred" |> Result.fold Choice1Of2 Choice2Of2 // choice2 will be Choice2Of2 "An error occurred" ``` ``` -------------------------------- ### Bind with Existing Account Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskOption/bind.md Demonstrates using TaskOption.bind to chain a lookup function with a Task containing an existing account's email. ```fsharp let taskOpt : Task = TaskOption.some "john@test.com" // Task |> TaskOption.bind lookupAccountByEmail // Task // task { Some { EmailAddress = "john@test.com"; Name = "John Johnson" } } ``` -------------------------------- ### Define remainingCharacters function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/result/apply.md Defines a function to calculate the remaining characters of a Tweet. This is a helper function for the subsequent examples. ```fsharp // Tweet -> int let remainingCharacters (tweet : Tweet) = 280 - tweet.Value.Length ``` -------------------------------- ### Partition Results after mapping Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/list/partitionResults.md Shows how to use List.partitionResults after mapping a list of strings to Results, handling potential parsing errors. ```fsharp // string -> Result let tryParseInt str = match System.Int32.TryParse str with | true, x -> Ok x | false, _ -> Error (sprintf "unable to parse '%s' to integer" str) ["1"; "foo"; "3"; "bar"] |> List.map tryParseInt |> List.partitionResults // ([1; 3], ["unable to parse 'foo' to integer"; "unable to parse 'bar' to integer"]) ``` -------------------------------- ### Define a logging function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/teeFunctions.md A helper function to log messages to the console. This is used in the examples to demonstrate side effects. ```fsharp let log (message: string) = printfn "%s" message ``` -------------------------------- ### Chaining with tryParseInt and bind Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/jobOption/bind.md This example demonstrates chaining a synchronous parsing operation (tryParseInt) with an asynchronous lookup (tryFindPersonById) using bind. The result is a Job, short-circuiting to None if parsing fails or the person is not found. ```fsharp tryParseInt : string -> int option tryFindPersonById : int -> Job // Job job { return tryParseInt "3001" } |> JobOption.bind tryFindPersonById ``` -------------------------------- ### Define a simple function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskOption/apply.md Defines a basic function that counts the characters in a string. This function will be used in subsequent examples. ```fsharp // string -> int let characterCount (s: string) = s.Length ``` -------------------------------- ### Using TaskResultOption Operators for Chaining Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskResultOption/operators.md Demonstrates how to use the map (), apply (<*>), and bind (>>=) operators for TaskResultOption. This allows for cleaner chaining of operations involving Task and Result types with optional values. ```fsharp open FsToolkit.ErrorHandling.Operator.TaskResult // Task> userTweet (getPostById samplePostId) <*> (getUserById sampleUserId) ``` -------------------------------- ### Get value when key does not exist Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/tryGetValue.md Demonstrates using Option.tryGetValue when the specified key is not present in the dictionary. The result is None. ```fsharp open System.Collections.Generic let dict = Dictionary() dict["apples"] <- 5 let result : int option = dict |> Option.tryGetValue "bananas" // None ``` -------------------------------- ### Async Customer Retrieval Function Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/traverseTask.md An asynchronous function to retrieve a Customer by email. This example returns a constant value for simplicity. ```fsharp // string -> Task let getCustomerByEmail email : Task = task { return { Id = 1; Email = "test@test.com" } // return a constant for simplicity } ``` -------------------------------- ### Bind with None Input Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableValueTaskOption/bind.md Demonstrates using CancellableValueTaskOption.bind when the initial task results in None, propagating the None. ```fsharp let taskOpt : CancellableValueTask = CancellableValueTask.singleton None // CancellableValueTask |> CancellableValueTaskOption.bind lookupAccountByEmail // CancellableValueTask // cancellableValueTask { None } ``` -------------------------------- ### Traverse OptionM with successful parsing Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/traverseOptionM.md Demonstrates successful parsing of all elements in a list using `traverseOptionM`. Each string is converted to an integer, and all succeed, resulting in `Some` containing the list of integers. ```fsharp let tryParseInt (s: string) = match Int32.TryParse(s) with | true, i -> Some i | false, _ -> None let myList = ["123"; "456"; "789"] List.traverseOptionM tryParseInt myList // Some [123; 456; 789] ``` -------------------------------- ### Map Error in JobResult Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/jobResult/mapError.md Use JobResult.mapError to transform the error type of a JobResult. This example converts an exception to its message string. ```fsharp // Job, string> createPost createPostRequest |> JobResult.mapError (fun (ex : exn) -> ex.Message) ``` -------------------------------- ### CancellableTaskValidation.parallelZip Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskValidation/parallelZip.md Takes two CancellableTaskValidation values, starts them concurrently, and returns a tuple of the results once both complete. Errors from both computations are accumulated. ```APIDOC ## CancellableTaskValidation.parallelZip ### Description Combines two `CancellableTaskValidation` computations to run in parallel, accumulating errors. Both computations are started before waiting for either to complete, which can improve throughput when the two operations are independent. ### Function Signature ```fsharp CancellableTaskValidation<'left, 'error> -> CancellableTaskValidation<'right, 'error> -> CancellableTaskValidation<'left * 'right, 'error> ``` ### Examples #### Example 1: Fetching two independent resources in parallel ```fsharp let validateUserAndRole (userId: UserId) : CancellableTaskValidation = CancellableTaskValidation.parallelZip (fetchAndValidateUser userId) (fetchAndValidateRole userId) ``` #### Example 2: Using `parallelZip` inside a computation expression ```fsharp let buildProfile (userId: UserId) : CancellableTaskValidation = cancellableTaskValidation { let! user, preferences = CancellableTaskValidation.parallelZip (fetchUser userId) (fetchPreferences userId) return UserProfile.create user preferences } ``` #### Example 3: Concurrently validating independent fields and accumulating all errors ```fsharp let validateSignupForm (form: SignupForm) : CancellableTaskValidation = CancellableTaskValidation.parallelZip (validateEmail form.Email) // e.g. Error ["Invalid email format"] (validateUsername form.Username) // e.g. Error ["Username too short"] // Both run concurrently; if both fail: Error ["Invalid email format"; "Username too short"] ``` ``` -------------------------------- ### Login Flow with Error Handling Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/README.md Demonstrates composing a login flow using a computation expression and helper functions for robust error handling. It handles various potential errors like invalid user, invalid password, authorization failures, and token creation issues. ```F# // Given the following functions: // tryGetUser: string -> Async // isPwdValid: string -> User -> bool // authorize: User -> Async> // createAuthToken: User -> Result type LoginError = InvalidUser | InvalidPwd | Unauthorized of AuthError | TokenErr of TokenError let login (username: string) (password: string) : Async> = asyncResult { // requireSome unwraps a Some value or gives the specified error if None let! user = username |> tryGetUser |> AsyncResult.requireSome InvalidUser // requireTrue gives the specified error if false do! user |> isPwdValid password |> Result.requireTrue InvalidPwd // Error value is wrapped/transformed (Unauthorized has signature AuthError -> LoginError) do! user |> authorize |> AsyncResult.mapError Unauthorized // Same as above, but synchronous, so we use the built-in mapError return! user |> createAuthToken |> Result.mapError TokenErr } ``` -------------------------------- ### Convert Some Option to AsyncResultOption Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/asyncResultOption/ofOption.md Use AsyncResultOption.ofOption to wrap a 'Some' value. The output is an async computation that resolves to an Ok variant containing the original Some value. ```fsharp let result = AsyncResultOption.ofOption (Some 42) // async { return Ok (Some 42) } ``` -------------------------------- ### Handle None case with TaskOption.either Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskOption/either.md When the input is None, the second provided task is executed. This example demonstrates handling a None value. ```fsharp TaskOption.either (fun x -> x * 2) (task { 0 }) None // task { 0 } ``` -------------------------------- ### Partitioning an All-Ok Array Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/array/partitionResults.md Demonstrates the behavior of Array.partitionResults when all elements in the input array are Ok values. The Error array will be empty. ```fsharp [| Ok 1; Ok 2; Ok 3 |] |> Array.partitionResults // ([| 1; 2; 3 |], [||]) ``` -------------------------------- ### Execute function for None value with Option.either Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/option/either.md When the option is None, the second function is executed. This example returns a default value of 0. ```fsharp Option.either (fun x -> x * 2) (fun () -> 0) None // 0 ``` -------------------------------- ### Collect All Errors Example Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/cancellableTaskValidation/operators.md Demonstrates how validateCreatePostRequest collects all validation errors when provided with invalid inputs, resulting in a list of error messages. ```fsharp validateCreatePostRequest 300. 400. "" // Error ["300.0 is a invalid latitude value" "400.0 is a invalid longitude value" "Tweet shouldn't be empty"] ``` -------------------------------- ### Partition a list of all Ok values Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/list/partitionResults.md Illustrates the behavior of List.partitionResults when the input list contains only Ok values. ```fsharp [Ok 1; Ok 2; Ok 3] |> List.partitionResults // ([1; 2; 3], []) ``` -------------------------------- ### Execute task based on ValueNone Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/taskValueOption/either.md When the input is ValueNone, the second function (a default task) is executed. This example returns a task with a value of 0. ```fsharp TaskValueOption.either (fun x -> task { x * 2 }) (task { 0 }) ValueNone // task { 0 } ``` -------------------------------- ### Traverse list with asynchronous fetch and stop on first error Source: https://github.com/demystifyfp/fstoolkit.errorhandling/blob/master/gitbook/list/traverseJobResultM.md This example demonstrates traversing a list of IDs to fetch user data asynchronously. It uses `List.traverseJobResultM` to handle operations returning `Job>`, ensuring that if any user fetch fails, the entire operation stops and returns the error. ```fsharp // int -> Job> let fetchUser : UserId -> Job> [userId1; userId2; userId3] |> List.traverseJobResultM fetchUser // job { return Ok [user1; user2; user3] } // or Error at the first user that fails to fetch ```