Skip to content

Commit

Permalink
feat(Seq)!: Add sequenceResultA, align sequenceResultM (#255)
Browse files Browse the repository at this point in the history
* Roll on '24

* refactor(Seq.sequenceResultM)!: Change Ok to Array

* docs: sequenceResultM

* feat(Seq): sequenceResultA

* f sequenceResultM docs

* Supress compile error

* Fix proposed version
  • Loading branch information
bartelink authored and TheAngryByrd committed Dec 7, 2024
1 parent 0a5fbf0 commit 3163462
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 518 deletions.
5 changes: 5 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@

### 5.0.0-alpha.1
- [refactor!: Seq.sequenceResultM returns Array instead of seq](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/255) [@bartelink](https://github.com/bartelink)
- [feat(Seq): sequenceResultA](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/255) [@bartelink](https://github.com/bartelink)

### 4.18.0 - October 23, 2024
- [Add Array errorhandling](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/279) Credits @DashieTM

Expand Down
4 changes: 3 additions & 1 deletion build/build.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
<!-- <NoWarn>NU1904</NoWarn>-->
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Include="DotEnv.fs" />
<Compile Include="build.fs" />
</ItemGroup>
<Import Project="..\.paket\Paket.Restore.targets" />
</Project>
</Project>
2 changes: 1 addition & 1 deletion gitbook/list/sequenceResultA.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ let checkIfAllPrime (numbers : int list) =
numbers
|> List.map isPrime // Result<bool, string> list
|> List.sequenceResultA // Result<bool list, string list>
|> Result.map (List.forall id) // shortened version of '|> Result.map (fun boolList -> boolList |> List.map (fun x -> x = true))'
|> Result.map (List.forall id) // shortened version of '|> Result.map (fun boolList -> boolList |> List.forall (fun x -> x = true))
let a = [1; 2; 3; 4; 5;] |> checkIfAllPrime
// Error ["1 must be greater than 1"]
Expand Down
44 changes: 19 additions & 25 deletions gitbook/seq/sequenceResultA.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ Namespace: `FsToolkit.ErrorHandling`
## Function Signature

```fsharp
Result<'a, 'b> seq -> Result<'a seq, 'b seq>
seq<Result<'a, 'b>> -> Result<'a[], 'b[]>
```

Note that `sequence` is the same as `traverse id`. See also [Seq.traverseResultA](traverseResultA.md).

This is applicative, collecting all errors. Compare the example below with [sequenceResultM](sequenceResultM.md).

See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpforfunandprofit.com/posts/elevated-world-4/).
Expand All @@ -23,53 +21,49 @@ See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpfo
let tryParseInt str =
match Int32.TryParse str with
| true, x -> Ok x
| false, _ ->
Error (sprintf "unable to parse '%s' to integer" str)
| false, _ -> Error $"unable to parse '{str}' to integer"
["1"; "2"; "3"]
|> Seq.map tryParseInt
|> Seq.sequenceResultA
// Ok [1; 2; 3]
// Ok [| 1; 2; 3 |]
["1"; "foo"; "3"; "bar"]
|> Seq.map tryParseInt
|> Seq.sequenceResultA
// Error ["unable to parse 'foo' to integer";
// "unable to parse 'bar' to integer"]
// Error [| "unable to parse 'foo' to integer"
// "unable to parse 'bar' to integer" |]
```

### Example 2

```fsharp
// int -> Result<bool, string>
let isPrime (x : int) =
if x < 2 then
sprintf "%i must be greater than 1" x |> Error
elif
x = 2 then Ok true
let isPrime (x: int) =
if x < 2 then Error $"{x} must be greater than 1"
elif x = 2 then Ok true
else
let rec isPrime' (x : int) (i : int) =
if i * i > x then Ok true
elif x % i = 0 then Ok false
else isPrime' x (i + 1)
isPrime' x 2
// int seq -> Result<bool, string seq>
let checkIfAllPrime (numbers : int seq) =
numbers
|> Seq.map isPrime // Result<bool, string> seq
|> Seq.sequenceResultA // Result<bool seq, string seq>
|> Result.map (Seq.forall id) // shortened version of '|> Result.map (fun boolSeq -> boolSeq |> Seq.map (fun x -> x = true))'
// seq<int> -> Result<bool, string[]>
let checkIfAllPrime (numbers: seq<int>) =
seq { for x in numbers -> isPrime x } // Result<bool, string> seq
|> Seq.sequenceResultA // Result<bool[], string[]>
|> Result.map (Seq.forall id) // shortened version of '|> Result.map (fun results -> results |> Array.forall (fun x -> x = true))'
let a = [1; 2; 3; 4; 5;] |> checkIfAllPrime
// Error ["1 must be greater than 1"]
let a = [| 1; 2; 3; 4; 5 |] |> checkIfAllPrime
// Error [| "1 must be greater than 1" |]
let b = [1; 2; 3; 4; 5; 0;] |> checkIfAllPrime
// Error ["1 must be greater than 1"; "0 must be greater than 1"]
let b = [ 1; 2; 3; 4; 5; 0 ] |> checkIfAllPrime
// Error [| "1 must be greater than 1"; "0 must be greater than 1" |]
let a = [2; 3; 4; 5;] |> checkIfAllPrime
let a = seq { 2; 3; 4; 5 } |> checkIfAllPrime
// Ok false
let a = [2; 3; 5;] |> checkIfAllPrime
let a = seq { 2; 3; 5 } |> checkIfAllPrime
// Ok true
```
39 changes: 17 additions & 22 deletions gitbook/seq/sequenceResultM.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ Namespace: `FsToolkit.ErrorHandling`
## Function Signature

```fsharp
Result<'a, 'b> seq -> Result<'a seq, 'b>
seq<Result<'a, 'b>> -> Result<'a[], 'b>
```

Note that `sequence` is the same as `traverse id`. See also [Seq.traverseResultM](traverseResultM.md).

This is monadic, stopping on the first error. Compare the example below with [sequenceResultA](sequenceResultA.md).

See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpforfunandprofit.com/posts/elevated-world-4/).
Expand All @@ -23,15 +21,14 @@ See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpfo
let tryParseInt str =
match Int32.TryParse str with
| true, x -> Ok x
| false, _ ->
Error (sprintf "unable to parse '%s' to integer" str)
| false, _ -> Error $"unable to parse '{str}' to integer"
["1"; "2"; "3"]
|> Seq.map tryParseInt
|> Seq.sequenceResultM
// Ok [1; 2; 3]
// Ok [| 1; 2; 3 |]
["1"; "foo"; "3"; "bar"]
seq { "1"; "foo"; "3"; "bar" }
|> Seq.map tryParseInt
|> Seq.sequenceResultM
// Error "unable to parse 'foo' to integer"
Expand All @@ -41,32 +38,30 @@ let tryParseInt str =

```fsharp
// int -> Result<bool, string>
let isPrime (x : int) =
if x < 2 then
sprintf "%i must be greater than 1" x |> Error
elif
x = 2 then Ok true
let isPrime (x: int) =
if x < 2 then Error $"{x} must be greater than 1"
elif x = 2 then Ok true
else
let rec isPrime' (x : int) (i : int) =
if i * i > x then Ok true
elif x % i = 0 then Ok false
else isPrime' x (i + 1)
isPrime' x 2
// int seq -> Result<bool, string seq>
let checkIfAllPrime (numbers : int seq) =
// int seq -> Result<bool, string[]>
let checkIfAllPrime (numbers: seq<int>) =
numbers
|> Seq.map isPrime // Result<bool, string> seq
|> Seq.sequenceResultM // Result<bool seq, string>
|> Result.map (Seq.forall id) // shortened version of '|> Result.map (fun boolSeq -> boolSeq |> Seq.map (fun x -> x = true))';
|> Seq.map isPrime // seq<Result<bool, string>>
|> Seq.sequenceResultM // Result<bool[], string>
|> Result.map (Array.forall id) // shortened version of '|> Result.map (fun bools -> bools |> Array.forall (fun x -> x = true))'
let a = [1; 2; 3; 4; 5;] |> checkIfAllPrime
// Error ["1 must be greater than 1"]
let a = [ 1; 2; 3; 4; 5 ] |> checkIfAllPrime
// Error [| "1 must be greater than 1" |]
let b = [1; 2; 3; 4; 5; 0;] |> checkIfAllPrime
// Error ["1 must be greater than 1"]
let b = [| 1; 2; 3; 4; 5; 0 |] |> checkIfAllPrime
// Error [| "1 must be greater than 1" |]
let a = [2; 3; 4; 5;] |> checkIfAllPrime
let a = seq { 2; 3; 4; 5 } |> checkIfAllPrime
// Ok false
let a = [2; 3; 5;] |> checkIfAllPrime
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<PropertyGroup>
<Description>FsToolkit.ErrorHandling is an extensive utility library based around the F# Result type, enabling consistent and powerful error handling.</Description>
<Authors>demystifyfp, TheAngryByrd</Authors>
<Copyright>Copyright © 2018-23</Copyright>
<Copyright>Copyright © 2018-24</Copyright>
<PackageProjectUrl>https://demystifyfp.gitbook.io/fstoolkit-errorhandling</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile> <!--https://docs.microsoft.com/en-gb/nuget/reference/msbuild-targets#packagereadmefile -->
Expand Down
4 changes: 1 addition & 3 deletions src/FsToolkit.ErrorHandling/Seq.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
namespace FsToolkit.ErrorHandling

[<RequireQualifiedAccess>]
module Seq =
module FsToolkit.ErrorHandling.Seq

/// <summary>
/// Applies a function to each element of a sequence and returns a single result
Expand Down
Loading

0 comments on commit 3163462

Please sign in to comment.