Skip to content

Commit deda884

Browse files
1eyewonderTheAngryByrd
authored andcommitted
Added sequence and traverse VOptionM
1 parent 75bdb37 commit deda884

File tree

2 files changed

+87
-0
lines changed
  • src/FsToolkit.ErrorHandling
  • tests/FsToolkit.ErrorHandling.Tests

2 files changed

+87
-0
lines changed

src/FsToolkit.ErrorHandling/List.fs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,24 @@ module List =
163163
traverseAsyncOptionM' (AsyncOption.retn []) f xs
164164

165165
let sequenceAsyncOptionM xs = traverseAsyncOptionM id xs
166+
167+
let rec private traverseVOptionM' (state: voption<_>) (f: _ -> voption<_>) xs =
168+
match xs with
169+
| [] ->
170+
state
171+
|> ValueOption.map List.rev
172+
| x :: xs ->
173+
let r =
174+
voption {
175+
let! y = f x
176+
let! ys = state
177+
return y :: ys
178+
}
179+
180+
match r with
181+
| ValueSome _ -> traverseVOptionM' r f xs
182+
| ValueNone -> r
183+
184+
let traverseVOptionM f xs = traverseVOptionM' (ValueSome []) f xs
185+
186+
let sequenceVOptionM xs = traverseVOptionM id xs

tests/FsToolkit.ErrorHandling.Tests/List.fs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,70 @@ let sequenceAsyncResultATests =
547547
}
548548
]
549549

550+
let traverseVOptionMTests =
551+
testList "List.traverseVOptionM Tests" [
552+
let tryTweetVOption x =
553+
match x with
554+
| x when String.IsNullOrEmpty x -> ValueNone
555+
| _ -> ValueSome x
556+
557+
testCase "traverseVOption with a list of valid data"
558+
<| fun _ ->
559+
let tweets = [
560+
"Hi"
561+
"Hello"
562+
"Hola"
563+
]
564+
565+
let expected = ValueSome tweets
566+
let actual = List.traverseVOptionM tryTweetVOption tweets
567+
568+
Expect.equal actual expected "Should have a list of valid tweets"
569+
570+
testCase "traverseVOption with few invalid data"
571+
<| fun _ ->
572+
let tweets = [
573+
"Hi"
574+
"Hello"
575+
String.Empty
576+
]
577+
578+
let actual = List.traverseVOptionM tryTweetVOption tweets
579+
Expect.equal actual ValueNone "traverse the list and return value none"
580+
]
581+
582+
let sequenceVOptionMTests =
583+
testList "List.sequenceVOptionM Tests" [
584+
let tryTweetOption x =
585+
match x with
586+
| x when String.IsNullOrEmpty x -> ValueNone
587+
| _ -> ValueSome x
588+
589+
testCase "traverseVOption with a list of valid data"
590+
<| fun _ ->
591+
let tweets = [
592+
"Hi"
593+
"Hello"
594+
"Hola"
595+
]
596+
597+
let expected = ValueSome tweets
598+
let actual = List.sequenceVOptionM (List.map tryTweetOption tweets)
599+
600+
Expect.equal actual expected "Should have a list of valid tweets"
601+
602+
testCase "sequenceVOptionM with few invalid data"
603+
<| fun _ ->
604+
let tweets = [
605+
String.Empty
606+
"Hello"
607+
String.Empty
608+
]
609+
610+
let actual = List.sequenceVOptionM (List.map tryTweetOption tweets)
611+
Expect.equal actual ValueNone "traverse the list and return value none"
612+
]
613+
550614
let allTests =
551615
testList "List Tests" [
552616
traverseResultMTests
@@ -563,4 +627,6 @@ let allTests =
563627
sequenceAsyncResultMTests
564628
sequenceAsyncOptionMTests
565629
sequenceAsyncResultATests
630+
traverseVOptionMTests
631+
sequenceVOptionMTests
566632
]

0 commit comments

Comments
 (0)