Very often when writing generic code in F# I come by a situation similar to this (I know this is quite inefficient, just for demonstration purposes):
let isPrime n =
let sq = n |> float |> sqrt |> int
{2..sq} |> Seq.forall (fun d -> n % d <> 0)
For many problems I can use statically resolved types and get even a performance boost due to inlining.
let inline isPrime (n:^a) =
let two = LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne
let sq = n |> float |> sqrt |> int
{two..sq} |> Seq.forall (fun d -> n % d <> LanguagePrimitives.GenericZero)
The code above won't compile because of the upper sequence limit being a float. Nongenerically, I could just cast back to int
for example.
But the compiler won't let me use any of these:
let sq = n |> float |> sqrt :> ^a
let sq = n |> float |> sqrt :?> ^a
and these two lead to a InvalidCastException
:
let sq = n |> float |> sqrt |> box |> :?> ^a
let sq = n |> float |> sqrt |> box |> unbox
Also, upcast
and downcast
are forbidden.
let sq = System.Convert.ChangeType(n |> float |> sqrt, n.GetType()) :?> ^a
works, but seems very cumbersome to me.
Is there a way that I overlooked or do I really have to use the last version? Because the last one will also break for bigint
, which I need quite often.
With the trick from FsControl, we can define generic function fromFloat
:
open FsControl.Core
type FromFloat = FromFloat with
static member instance (FromFloat, _:int32 ) = fun (x:float) -> int x
static member instance (FromFloat, _:int64 ) = fun (x:float) -> int64 x
static member instance (FromFloat, _:bigint ) = fun (x:float) -> bigint x
let inline fromFloat (x:float):^a = Inline.instance FromFloat x
let inline isPrime (n:^a) =
let two = LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne
let sq = n |> float |> sqrt |> fromFloat
{two..sq} |> Seq.forall (fun d -> n % d <> LanguagePrimitives.GenericZero)
printfn "%A" <| isPrime 71
printfn "%A" <| isPrime 6L
printfn "%A" <| isPrime 23I
Inline.instance was defined here.
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