F# Equivalent to Enumerable.OfType<'a>

Posted by Joel Mueller on Stack Overflow See other posts from Stack Overflow or by Joel Mueller
Published on 2010-03-26T05:11:57Z Indexed on 2010/03/26 5:13 UTC
Read the original article Hit count: 369

Filed under:

...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.

© Stack Overflow or respective owner

Related posts about F#