Search code examples
.netf#.net-standard-2.0system.memoryhighperformance

How to iterate over ReadOnlySpan in F#?


You can get Spans via System.Memory to.NET Standard 2.0 compatible libraries.

But how do you do this the most efficiently in F#:

let myRsp = "test1".AsSpan()
let test = Seq.forall (fun x -> Char.IsLower x) myRsp 

ReadOnlySpan<char> seems not to be compatible with Seq/Array/List and doing .ToArray() is making a copy. And if you try something like seq { for c in myRsp do yield (Char.IsLower c) } |> Seq.forall id you cannot do it because seq { } is like a function and you cannot transfer ReadOnlySpan<char> easily between functions.


Solution

  • Unfortunately, there's no good way to turn a ReadOnlySpan into an F# sequence and the compiler won't help paper over the difference (unlike the C# compiler). So, given those limitations, here's how I would do it:

    module ReadOnlySpan =
    
        let forall predicate (source : ReadOnlySpan<_>) =
            let mutable state = true
            let mutable e = source.GetEnumerator()
            while state && e.MoveNext() do
                state <- predicate e.Current
            state
    

    Test:

    let myRsp = "test1".AsSpan()
    let test = ReadOnlySpan.forall Char.IsLower myRsp
    printfn "%A" test   // false
    

    This isn't really much better than your solution, but it's a bit cleaner and mimics the F# core implementation of Seq.forall.