From fb1dd182d4ac9b106ed1767268ae0ddf8b594f40 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Mon, 19 Jan 2026 13:11:30 +0800 Subject: [PATCH 1/6] tests: improve test names for skipNoFail --- tests/FSharpx.Collections.Tests/SeqTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharpx.Collections.Tests/SeqTests.fs b/tests/FSharpx.Collections.Tests/SeqTests.fs index 1d334e63..2689f1df 100644 --- a/tests/FSharpx.Collections.Tests/SeqTests.fs +++ b/tests/FSharpx.Collections.Tests/SeqTests.fs @@ -138,9 +138,9 @@ module SeqTests = test "I should get some if try to get a index inside the seq" { Seq.tryNth 2 data |> Expect.equal "tryNth" (Some(3.)) } - test "I should get none when trySkip past the end of the seq" { Seq.skipNoFail 20 data |> Expect.sequenceEqual "skipNoFail" Seq.empty } + test "I should get empty seq when skipNoFail past the end of the seq" { Seq.skipNoFail 20 data |> Expect.sequenceEqual "skipNoFail" Seq.empty } - test "I should get Some when trySkip" { + test "I should get Some when skipNoFail" { Seq.skipNoFail 5 data |> Expect.sequenceEqual "skipNoFail" (List.toSeq [ 6.; 7.; 8.; 9.; 10. ]) } From 729f5117f5c191a70dff665b4a4406981f67605c Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Mon, 19 Jan 2026 13:14:13 +0800 Subject: [PATCH 2/6] tests: add failing tests for trySkip --- tests/FSharpx.Collections.Tests/SeqTests.fs | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/FSharpx.Collections.Tests/SeqTests.fs b/tests/FSharpx.Collections.Tests/SeqTests.fs index 2689f1df..816e5820 100644 --- a/tests/FSharpx.Collections.Tests/SeqTests.fs +++ b/tests/FSharpx.Collections.Tests/SeqTests.fs @@ -74,6 +74,32 @@ module SeqTests = | _ -> failwith "Unreachable" } + test "If I trySkip and I don't have a head, I should return None" { Seq.empty |> Seq.trySkip 1 |> Expect.isNone "trySkip1" } + + test "If I trySkip1 a non-empty seq, I should return just tail" { + let data = [ 1; 2; 3 ] + let actual = data |> Seq.trySkip 1 + Expect.isSome "trySkip1" actual + + match actual with + | Some subSeq -> Expect.sequenceEqual "trySkip1" [ 2; 3 ] subSeq + | _ -> failwith "Unreachable" + } + + test "If I trySkip2 a non-empty seq, I should return just last" { + let data = [ 1; 2; 3 ] + let actual = data |> Seq.trySkip 2 + Expect.isSome "trySkip2" actual + + match actual with + | Some subSeq -> Expect.sequenceEqual "trySkip2" [ 3 ] subSeq + | _ -> failwith "Unreachable" + } + + test "If I trySkip2 and seq only contains 1 element, I should return None" { + seq { yield 1 } |> Seq.trySkip 2 |> Expect.isNone "trySkip2" + } + test "I should be a to split a seq at an index" { let (a, b) = Seq.splitAt 5 data Expect.sequenceEqual "splitAt" (List.toSeq [ 1.; 2.; 3.; 4.; 5. ]) a From c7844411acbb6014fb23c9332e77086042b445f1 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Wed, 7 Jan 2026 18:55:39 +0800 Subject: [PATCH 3/6] Seq extensions: add trySkip This way it is an alternative to Seq.skip: same but non-partial function (that doesn't throw exceptions), following same approach as tryHeadTail[1]. [1] fdbeaf21db4bfc0f446abbbf8b70d2bb60e5e65d --- src/FSharpx.Collections/Collections.fs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/FSharpx.Collections/Collections.fs b/src/FSharpx.Collections/Collections.fs index 1dff6f9f..d8fb7365 100644 --- a/src/FSharpx.Collections/Collections.fs +++ b/src/FSharpx.Collections/Collections.fs @@ -81,6 +81,15 @@ module Seq = let splitAt n seq = (Seq.take n seq, Seq.skip n seq) + /// The same as Seq.skip except will return None if not enough elements to skip or count passed is < 1 + let rec trySkip<'T> (count: int) (source: seq<'T>) : Option> = + if count < 1 then + None + else + match tryHeadTail source with + | None -> None + | Some(head, tail) -> if count = 1 then Some tail else trySkip (count - 1) tail + /// Splits a sequences up to the point where the predicate holds let span predicate source = (Seq.takeWhile predicate source, Seq.skipWhile predicate source) From b153d27e57f618d4011a64d3817d31fbc2caba56 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Wed, 7 Jan 2026 19:06:38 +0800 Subject: [PATCH 4/6] Seq.trySkip: mark with TailCall attrib This way the compiler will make sure that this recursive function will not cause stackoverflows. --- src/FSharpx.Collections/Collections.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FSharpx.Collections/Collections.fs b/src/FSharpx.Collections/Collections.fs index d8fb7365..0c2b8d48 100644 --- a/src/FSharpx.Collections/Collections.fs +++ b/src/FSharpx.Collections/Collections.fs @@ -82,6 +82,7 @@ module Seq = (Seq.take n seq, Seq.skip n seq) /// The same as Seq.skip except will return None if not enough elements to skip or count passed is < 1 + [] let rec trySkip<'T> (count: int) (source: seq<'T>) : Option> = if count < 1 then None From cdd89eabb3e982a1c46803869b67550528f796bc Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Mon, 19 Jan 2026 13:27:53 +0800 Subject: [PATCH 5/6] SeqTests: ran fantomas --- tests/FSharpx.Collections.Tests/SeqTests.fs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/FSharpx.Collections.Tests/SeqTests.fs b/tests/FSharpx.Collections.Tests/SeqTests.fs index 816e5820..757b62ac 100644 --- a/tests/FSharpx.Collections.Tests/SeqTests.fs +++ b/tests/FSharpx.Collections.Tests/SeqTests.fs @@ -91,9 +91,9 @@ module SeqTests = let actual = data |> Seq.trySkip 2 Expect.isSome "trySkip2" actual - match actual with - | Some subSeq -> Expect.sequenceEqual "trySkip2" [ 3 ] subSeq - | _ -> failwith "Unreachable" + match actual with + | Some subSeq -> Expect.sequenceEqual "trySkip2" [ 3 ] subSeq + | _ -> failwith "Unreachable" } test "If I trySkip2 and seq only contains 1 element, I should return None" { @@ -164,7 +164,9 @@ module SeqTests = test "I should get some if try to get a index inside the seq" { Seq.tryNth 2 data |> Expect.equal "tryNth" (Some(3.)) } - test "I should get empty seq when skipNoFail past the end of the seq" { Seq.skipNoFail 20 data |> Expect.sequenceEqual "skipNoFail" Seq.empty } + test "I should get empty seq when skipNoFail past the end of the seq" { + Seq.skipNoFail 20 data |> Expect.sequenceEqual "skipNoFail" Seq.empty + } test "I should get Some when skipNoFail" { Seq.skipNoFail 5 data From bbbff47d31aae065e8e2131a280e540ca766c23d Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Mon, 19 Jan 2026 17:57:09 +0800 Subject: [PATCH 6/6] WIP try upgrading paket manually --- paket.dependencies | 2 +- paket.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/paket.dependencies b/paket.dependencies index 075e0a2f..40bf08c0 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -1,7 +1,7 @@ framework: netstandard2.0, net8.0 source https://api.nuget.org/v3/index.json -nuget FSharp.Core >= 4.3.4 lowest_matching:true +nuget FSharp.Core >= 8.0.403 lowest_matching:true nuget Expecto nuget Expecto.FsCheck nuget FsCheck diff --git a/paket.lock b/paket.lock index c6d2ebce..b86b68d5 100644 --- a/paket.lock +++ b/paket.lock @@ -9,7 +9,7 @@ NUGET FsCheck (>= 2.14) FsCheck (2.16.6) FSharp.Core (>= 4.2.3) - FSharp.Core (4.3.4) + FSharp.Core (8.0.403) Microsoft.CodeCoverage (18.0.1) - restriction: || (== net8.0) (&& (== netstandard2.0) (>= net462)) (&& (== netstandard2.0) (>= net8.0)) Microsoft.NET.Test.Sdk (18.0.1) Microsoft.CodeCoverage (>= 18.0.1) - restriction: || (== net8.0) (&& (== netstandard2.0) (>= net462)) (&& (== netstandard2.0) (>= net8.0))