How to iterate over ReadOnlySpan in F#?
Asked Answered
P

2

5

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.

Pilloff answered 4/7 at 17:17 Comment(1)
learn.microsoft.com/en-us/dotnet/api/… is pretty spartan, but newer versions provide stuff like IndexOfAnyExceptInRange. Maybe you could port the impls of those back as shims? (No, none of those take predicates) So in general I guess you're left with copying Array impls and using while loops. The TaskSeq impls might be useful too for tested algorithms to copyPetroleum
M
5

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.

Masonmasonic answered 4/7 at 22:3 Comment(0)
P
1

Update: So far this is the best I've found:

let rec forAll (sub:inref<ReadOnlySpan<char>>) i =
    if i >= sub.Length then true
    else
    if Char.IsLower sub.[i] then
        forAll &sub (i+1)
    else false

let myRsp = "test1".AsSpan()
let test = forAll &myRsp 0
Pilloff answered 4/7 at 18:0 Comment(1)
ReaOnlySpan<T> doesn't implement IEnumerable<T>?Piano

© 2022 - 2024 — McMap. All rights reserved.