Skip to content

Commit 4a13d62

Browse files
committed
refactor(Seq.sequenceResultM)!: Change Ok to Array
1 parent dccdbbc commit 4a13d62

File tree

3 files changed

+45
-60
lines changed

3 files changed

+45
-60
lines changed

paket.dependencies

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
source https://api.nuget.org/v3/index.json
22

3-
43
storage: none
5-
64
nuget Microsoft.SourceLink.GitHub prerelease copy_local: true
75

86

9-
10-
117
group NetStandard2
128
source https://api.nuget.org/v3/index.json
139
lowest_matching: true
1410
strategy: min
15-
nuget FSharp.Core >= 4.7.2
11+
nuget FSharp.Core >= 4.7.2 content: none
1612
nuget Ply
1713
nuget Hopac
1814
nuget FSharp.Control.AsyncSeq
@@ -21,9 +17,6 @@ framework: netstandard2.0, net6.0
2117
storage: none
2218
condition: netstandard2_0
2319

24-
25-
26-
2720
group NetStandard2_1
2821
source https://api.nuget.org/v3/index.json
2922
lowest_matching: true
@@ -36,6 +29,7 @@ framework: netstandard2.1, net7.0
3629
storage: none
3730
condition: netstandard2_1
3831

32+
3933
group Test
4034
source https://api.nuget.org/v3/index.json
4135
storage: none
@@ -52,6 +46,7 @@ nuget Fable.Python
5246
nuget Fable.Pyxpecto
5347
nuget Ply
5448

49+
5550
group Benchmarks
5651
source https://api.nuget.org/v3/index.json
5752
storage: none
@@ -65,7 +60,7 @@ nuget BenchmarkDotNet.Diagnostics.Windows 0.13.1
6560
group Build
6661
source https://api.nuget.org/v3/index.json
6762
storage: none
68-
nuget FSharp.Core
63+
nuget FSharp.Core content: none
6964
nuget Fake.Core.Target 5.22.0
7065
nuget Fake.DotNet.Cli 5.22.0
7166
nuget Fake.Core.ReleaseNotes 5.22.0

src/FsToolkit.ErrorHandling/Seq.fs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
namespace FsToolkit.ErrorHandling
2-
31
[<RequireQualifiedAccess>]
4-
module Seq =
2+
module FsToolkit.ErrorHandling.Seq
3+
4+
let sequenceResultM (xs: seq<Result<'t, 'e>>) : Result<'t[], 'e> =
5+
if isNull xs then
6+
nullArg (nameof xs)
7+
8+
let acc = ResizeArray()
9+
let mutable err = Unchecked.defaultof<_>
10+
let mutable ok = true
11+
use e = xs.GetEnumerator()
512

6-
let sequenceResultM (xs: seq<Result<'t, 'e>>) : Result<'t seq, 'e> =
7-
let rec loop xs ts =
8-
match Seq.tryHead xs with
9-
| Some x ->
10-
x
11-
|> Result.bind (fun t -> loop (Seq.tail xs) (t :: ts))
12-
| None ->
13-
Ok(
14-
List.rev ts
15-
|> List.toSeq
16-
)
13+
while e.MoveNext()
14+
&& ok do
15+
match e.Current with
16+
| Ok r -> acc.Add r
17+
| Error e ->
18+
ok <- false
19+
err <- e
1720

18-
// Seq.cache prevents double evaluation in Seq.tail
19-
loop (Seq.cache xs) []
21+
if ok then Ok(acc.ToArray()) else Error err

tests/FsToolkit.ErrorHandling.Tests/Seq.fs

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
module SeqTests
22

3-
43
#if FABLE_COMPILER_PYTHON
54
open Fable.Pyxpecto
65
#endif
@@ -12,60 +11,50 @@ open Expecto
1211
#endif
1312
open SampleDomain
1413
open TestData
15-
open TestHelpers
16-
open System
1714
open FsToolkit.ErrorHandling
1815

19-
2016
let sequenceResultMTests =
2117
testList "Seq.sequenceResultM Tests" [
22-
testCase "traverseResult with an empty sequence"
18+
testCase "sequenceResult with an empty sequence"
2319
<| fun _ ->
24-
let tweets = []
25-
let expected = Ok []
20+
let tweets = Seq.empty
21+
let expected = Ok [||]
2622

27-
let actual =
28-
Seq.sequenceResultM (Seq.map Tweet.TryCreate tweets)
29-
|> Result.map Seq.toList
23+
let actual = Seq.sequenceResultM (Seq.map Tweet.TryCreate tweets)
3024

3125
Expect.equal actual expected "Should have an empty list of valid tweets"
3226

33-
testCase "traverseResult with a sequence of valid data"
27+
testCase "sequenceResult with a sequence of valid data"
3428
<| fun _ ->
35-
let tweets = [
36-
"Hi"
37-
"Hello"
38-
"Hola"
39-
]
29+
let tweets =
30+
seq {
31+
"Hi"
32+
"Hello"
33+
"Hola"
34+
}
4035

41-
let expected =
42-
List.map tweet tweets
43-
|> Ok
36+
let expected = Ok [| for x in tweets -> tweet x |]
4437

45-
let actual =
46-
Seq.sequenceResultM (Seq.map Tweet.TryCreate tweets)
47-
|> Result.map Seq.toList
38+
let actual = Seq.sequenceResultM (Seq.map Tweet.TryCreate tweets)
4839

4940
Expect.equal actual expected "Should have a list of valid tweets"
5041

51-
testCase "sequenceResultM with few invalid data"
42+
testCase "sequenceResult with few invalid data"
5243
<| fun _ ->
5344
let tweets =
54-
[
45+
seq {
5546
""
5647
"Hello"
5748
aLongerInvalidTweet
58-
]
59-
:> seq<_>
49+
}
50+
51+
let expected = Error emptyTweetErrMsg
6052

6153
let actual = Seq.sequenceResultM (Seq.map Tweet.TryCreate tweets)
6254

63-
Expect.equal
64-
actual
65-
(Error emptyTweetErrMsg)
66-
"traverse the sequence and return the first error"
55+
Expect.equal actual expected "traverse the sequence and return the first error"
6756

68-
testCase "sequenceResultM stops after first invalid data"
57+
testCase "sequenceResult stops after first invalid data"
6958
<| fun _ ->
7059
let mutable counter = 0
7160

@@ -81,12 +70,11 @@ let sequenceResultMTests =
8170
+ 1
8271
}
8372

73+
let expected = Error longerTweetErrMsg
74+
8475
let actual = Seq.sequenceResultM (Seq.map Tweet.TryCreate tweets)
8576

86-
Expect.equal
87-
actual
88-
(Error longerTweetErrMsg)
89-
"traverse the sequence and return the first error"
77+
Expect.equal actual expected "traverse the sequence and return the first error"
9078

9179
Expect.equal counter 0 "evaluation of the sequence stops at the first error"
9280
]

0 commit comments

Comments
 (0)