Casting to and from type parameter in F #

I am just starting to work in F #, and some of the questions related to casting really scare me. Unfortunately, my background reading is to try to figure out why it scares me even more, so I'm looking for some specific answers that I can fit into general explanations ...

I have ReadOnlyCollection <'T> of the enumerations created by this function:

let GetValues<'T when 'T :> Enum> () = (new ReadOnlyCollection<'T>(Enum.GetValues (typeof<'T>) :?> 'T[])) :> IList<'T> 

What I want to do with it is to find all the bits of the enumeration that are used by its values ​​(that is, bitwise or all the values ​​in the list together) and return it as a common type of enumeration, 'T, The obvious way to do this seemed to me as follows:

 let UsedBits<'T when 'T :> Enum> () = GetValues<'T>() |> Seq.fold (fun acc a -> acc ||| a) 0 

... except that it cannot be compiled with the error "A declared parameter of type" T "cannot be used here because the type parameter cannot be resolved at compile time."

I can get the actual work by first converting to Int32 (which I really don’t want to do, because I want this function to work on all enums regardless of the base type), namely:

 let UsedBits<'T when 'T :> Enum> () = GetValues<'T>() |> Seq.map (fun a -> Convert.ToInt32(a)) |> Seq.fold (fun acc a -> acc ||| a) 0 

... but then the result is obtained as Int32. If I try to return it back to "T", I get compilation errors again.

I do not want to be too specific in my question, because I am not sure what features I should ask, therefore - where are the shortcomings in this approach? How can I do it?

(Edited to add:, post @ Daniel answer

Alas, this is apparently one of those situations where I do not understand the context enough to understand the answer, therefore ...

I think I understand what inline does and the various limitations in your answer, but being a F # newbie, could you seriously expand it so that I can verify that my understanding is not moving away from the base? Thanks.

)

+4
source share
1 answer

You can do it:

 let GetValues<'T, 'U when 'T : enum<'U>>() = Enum.GetValues(typeof<'T>) :?> 'T[] let inline GetUsedBits() = GetValues() |> Seq.reduce (|||) 

inline allows a more flexible constraint, namely 'T (requires member ( ||| )) . Without this, the compiler must choose a constraint that can be expressed in IL, or if it cannot be done, select a specific type. In this case, it selects int since it supports (|||) .

Here's a simpler reprogramming:

 let Or ab = a ||| b //add 'inline' to compare 

See "Static Resolution Settings" on MSDN for details.

+8
source

All Articles