Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Equivalent to Enumerable.OfType<'a>

Tags:

f#

...or, how do I filter a sequence of classes by the interfaces they implement?

Let's say I have a sequence of objects that inherit from Foo, a seq<#Foo>. In other words, my sequence will contain one or more of four different subclasses of Foo.

Each subclass implements a different independent interface that shares nothing with the interfaces implemented by the other subclasses.

Now I need to filter this sequence down to only the items that implement a particular interface.

The C# version is simple:

    void MergeFoosIntoList<T>(IEnumerable<Foo> allFoos, IList<T> dest) 
        where T : class
    {
        foreach (var foo in allFoos)
        {
            var castFoo = foo as T;
            if (castFoo != null)
            {
                dest.Add(castFoo);
            }
        }
    }

I could use LINQ from F#:

    let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
            System.Linq.Enumerable.OfType<'a>(foos)
            |> Seq.iter dest.Add

However, I feel like there should be a more idiomatic way to accomplish it. I thought this would work...

    let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
            foos
            |> Seq.choose (function | :? 'a as x -> Some(x) | _ -> None)
            |> Seq.iter dest.Add

However, the complier complains about :? 'a - telling me:

This runtime coercion or type test from type 'b to 'a involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed.

I can't figure out what further type annotations to add. There's no relationship between the interface 'a and #Foo except that one or more subclasses of Foo implement that interface. Also, there's no relationship between the different interfaces that can be passed in as 'a except that they are all implemented by subclasses of Foo.

I eagerly anticipate smacking myself in the head as soon as one of you kind people points out the obvious thing I've been missing.

like image 903
Joel Mueller Avatar asked Mar 26 '10 05:03

Joel Mueller


People also ask

Facebook itu apa sih?

Facebook adalah media sosial dan layanan jejaring sosial online Amerika yang dimiliki oleh Meta Platforms.


1 Answers

You can do this:

let foos = candidates |> Seq.filter (fun x -> x :? Foo) |> Seq.cast<Foo>
like image 99
Mark Seemann Avatar answered Oct 02 '22 22:10

Mark Seemann