Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Array errorhandling #279

Merged
merged 1 commit into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 239 additions & 0 deletions src/FsToolkit.ErrorHandling/Array.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
namespace FsToolkit.ErrorHandling

[<RequireQualifiedAccess>]
module Array =
let rec private traverseResultM' (state: Result<_, _>) (f: _ -> Result<_, _>) xs =
match xs with
| [||] ->
state
|> Result.map Array.rev
| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr

let res =
result {
let! y = f x
let! ys = state
return Array.append [| y |] ys
}

match res with
| Ok _ -> traverseResultM' res f xs
| Error _ -> res

let rec private traverseAsyncResultM'
(state: Async<Result<_, _>>)
(f: _ -> Async<Result<_, _>>)
xs
=
match xs with
| [||] ->
state
|> AsyncResult.map Array.rev
| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr

async {
let! r =
asyncResult {
let! ys = state
let! y = f x
return Array.append [| y |] ys
}

match r with
| Ok _ -> return! traverseAsyncResultM' (Async.singleton r) f xs
| Error _ -> return r
}

let traverseResultM f xs = traverseResultM' (Ok [||]) f xs

let sequenceResultM xs = traverseResultM id xs

let traverseAsyncResultM f xs =
traverseAsyncResultM' (AsyncResult.retn [||]) f xs

let sequenceAsyncResultM xs = traverseAsyncResultM id xs

let rec private traverseResultA' state f xs =
match xs with
| [||] ->
state
|> Result.eitherMap Array.rev Array.rev
| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr

match state, f x with
| Ok ys, Ok y -> traverseResultA' (Ok(Array.append [| y |] ys)) f xs
| Error errs, Error e -> traverseResultA' (Error(Array.append [| e |] errs)) f xs
| Ok _, Error e -> traverseResultA' (Error [| e |]) f xs
| Error e, Ok _ -> traverseResultA' (Error e) f xs

let rec private traverseAsyncResultA' state f xs =
match xs with
| [||] ->
state
|> AsyncResult.eitherMap Array.rev Array.rev

| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr

async {
let! s = state
let! fR = f x

match s, fR with
| Ok ys, Ok y ->
return! traverseAsyncResultA' (AsyncResult.retn (Array.append [| y |] ys)) f xs
| Error errs, Error e ->
return!
traverseAsyncResultA'
(AsyncResult.returnError (Array.append [| e |] errs))
f
xs
| Ok _, Error e ->
return! traverseAsyncResultA' (AsyncResult.returnError [| e |]) f xs
| Error e, Ok _ -> return! traverseAsyncResultA' (AsyncResult.returnError e) f xs
}

let traverseResultA f xs = traverseResultA' (Ok [||]) f xs

let sequenceResultA xs = traverseResultA id xs

let rec private traverseValidationA' state f xs =
match xs with
| [||] ->
state
|> Result.eitherMap Array.rev Array.rev
| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr
let fR = f x

match state, fR with
| Ok ys, Ok y -> traverseValidationA' (Ok(Array.append [| y |] ys)) f xs
| Error errs1, Error errs2 ->
let errs = Array.append errs2 errs1
traverseValidationA' (Error errs) f xs
| Ok _, Error errs
| Error errs, Ok _ -> traverseValidationA' (Error errs) f xs

let traverseValidationA f xs = traverseValidationA' (Ok [||]) f xs

let sequenceValidationA xs = traverseValidationA id xs

let traverseAsyncResultA f xs =
traverseAsyncResultA' (AsyncResult.retn [||]) f xs

let sequenceAsyncResultA xs = traverseAsyncResultA id xs

let rec private traverseOptionM' (state: Option<_>) (f: _ -> Option<_>) xs =
match xs with
| [||] ->
state
|> Option.map Array.rev
| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr

let r =
option {
let! y = f x
let! ys = state
return Array.append [| y |] ys
}

match r with
| Some _ -> traverseOptionM' r f xs
| None -> r

let rec private traverseAsyncOptionM' (state: Async<Option<_>>) (f: _ -> Async<Option<_>>) xs =
match xs with
| [||] ->
state
|> AsyncOption.map Array.rev
| arr ->
let x = Array.head arr
let xs = Array.skip 1 arr

async {
let! o =
asyncOption {
let! y = f x
let! ys = state
return Array.append [| y |] ys
}

match o with
| Some _ -> return! traverseAsyncOptionM' (Async.singleton o) f xs
| None -> return o
}

/// <summary>
/// Applies the given function <paramref name="f"/> to each element in the input list <paramref name="xs"/>,
/// and returns an option containing a list of the results. If any of the function applications return None,
/// the entire result will be None.
/// </summary>
/// <param name="f">The function to apply to each element in the input list.</param>
/// <param name="xs">The input list.</param>
/// <returns>An option containing a list of the results of applying the function to each element in the input list,
/// or None if any of the function applications return None.</returns>
let traverseOptionM f xs = traverseOptionM' (Some [||]) f xs

/// <summary>
/// Applies the monadic function <paramref name="id"/> to each element in the input list <paramref name="xs"/>,
/// and returns the result as an option. If any element in the list is None, the entire result will be None.
/// </summary>
/// <param name="xs">The input list.</param>
/// <returns>An option containing the result of applying <paramref name="id"/> to each element in <paramref name="xs"/>.</returns>
let sequenceOptionM xs = traverseOptionM id xs

let traverseAsyncOptionM f xs =
traverseAsyncOptionM' (AsyncOption.retn [||]) f xs

let sequenceAsyncOptionM xs = traverseAsyncOptionM id xs

#if !FABLE_COMPILER
let rec private traverseVOptionM' (state: voption<_>) (f: _ -> voption<_>) xs =
match xs with
| [||] ->
state
|> ValueOption.map Array.rev
| arr ->
let x = Array.head arr
DashieTM marked this conversation as resolved.
Show resolved Hide resolved
let xs = Array.skip 1 arr

let r =
voption {
let! y = f x
let! ys = state
return Array.append [| y |] ys
}

match r with
| ValueSome _ -> traverseVOptionM' r f xs
| ValueNone -> r

/// <summary>
/// Applies the given function <paramref name="f"/> to each element in the input list <paramref name="xs"/>,
/// and returns an option containing a list of the results. If any of the function applications return ValueNone,
/// the entire result will be ValueNone.
/// </summary>
/// <param name="f">The function to apply to each element in the input list.</param>
/// <param name="xs">The input list</param>
/// <returns>An Option monad containing the collected results.</returns>
let traverseVOptionM f xs = traverseVOptionM' (ValueSome [||]) f xs

/// <summary>
/// Applies the <paramref name="id"/> function to each element in the input list <paramref name="xs"/>,
/// and returns the result as a value option. If any element in the list is ValueNone, the entire result will be ValueNone.
/// </summary>
/// <param name="xs">The input list.</param>
/// <returns>A <see cref="Option{T}"/> representing the sequence of results.</returns>
let sequenceVOptionM xs = traverseVOptionM id xs

#endif
1 change: 1 addition & 0 deletions src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<Compile Include="AsyncResultOptionCE.fs" />
<Compile Include="AsyncResultOptionOp.fs" />
<Compile Include="List.fs" />
<Compile Include="Array.fs" />
<Compile Include="Seq.fs" />
<None Include="Script.fsx" />
<None Include="paket.references" />
Expand Down
Loading
Loading