I created a pipe-able ofType<'T>
function for sequences based on Enumerable.OfType<'T>()
:
let ofType<'T> (sequence : _ seq) = sequence.OfType<'T>()
Using this within the same .fsx
file works fine; it still does when I put it into a module:
module Seq =
let ofType<'T> (sequence : _ seq) = sequence.OfType<'T>()
It stops working when I move it into another script file and (to be able to access it from elsewhere) wrap it in another top-level module:
module Prelude =
open System.Linq
module Seq =
let ofType<'T> (sequence : _ seq) = sequence.OfType<'T>()
I reference this from my original script file, open the Prelude
module and call the function like this:
let getXmlIncludes (xtype : Type) =
xtype.GetCustomAttributes() |> Seq.ofType<XmlIncludeAttribute>
That causes Seq.ofType<XmlIncludeAttribute>
to be marked as an error, with the message
error FS0001: Type mismatch. Expecting a
Collections.Generic.IEnumerable<Attribute> -> 'a
> but given a
Collections.Generic.IEnumerable<Attribute> -> Collections.Generic.IEnumerable<XmlIncludeAttribute>
The type 'obj' does not match the type 'Attribute'
The error remains the same when I move ofType<'T>
directly into the Prelude
module.
Why does this happen, and how can I make it not happen?
(I tried changing the _ seq
type for the sequence
parameter to 'TSeq seq
, which results in the ever-popular
warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'TSeq has been constrained to be type 'obj'.
but doesn't change anything about the error.)
The actual type arguments of a generic type are. reference types, wildcards, or. parameterized types (i.e. instantiations of other generic types).
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class.
Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
Enumerable.OfType<'T>()
is not generic with regards to input parameter. After changing _ seq
to non-generic IEnumerable
the error disappears.
open System
open System.Collections
open System.Reflection
open System.Xml.Serialization
module Prelude =
open System.Linq
module Seq =
let inline ofType<'T> (sequence : IEnumerable) = sequence.OfType<'T>()
open Prelude
let getXmlIncludes (xtype : Type) =
xtype.GetCustomAttributes() |> Seq.ofType<XmlIncludeAttribute>
In your original code (sequence : _ seq)
is constrained to seq<Attribute>
, but F# does not support type covariance and cannot work with seq<XmlIncludeAttribute>
as if it was seq<Attribute>
, even though XmlIncludeAttribute
inherits Attribute
. But even if F# had supported covariance, your example would have worked only for this particular case plus only for types that inherit from Attribute
.
You could clearly see the error if you try to use your Seq extension with a different type:
let getIntsAsUints (list : List<int>) =
list |> Seq.ofType<uint32>
Script.fsx(21,13): error FS0001: The type 'List<int>' is not compatible with the type 'seq<Attribute>'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With