pri*_*tor 10 f# static-analysis casting compile-time
通常在F#中编写通用代码时,我会遇到与此类似的情况(我知道这非常低效,仅用于演示目的):
let isPrime n =
let sq = n |> float |> sqrt |> int
{2..sq} |> Seq.forall (fun d -> n % d <> 0)
Run Code Online (Sandbox Code Playgroud)
对于许多问题,我可以使用静态解析的类型,并通过内联获得性能提升.
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)
Run Code Online (Sandbox Code Playgroud)
由于上限序列是一个浮点数,上面的代码将无法编译.非理性地说,我可以退回到int例如.
但是编译器不允许我使用以下任何一个:
let sq = n |> float |> sqrt :> ^alet sq = n |> float |> sqrt :?> ^a这两个导致InvalidCastException:
let sq = n |> float |> sqrt |> box |> :?> ^alet sq = n |> float |> sqrt |> box |> unbox此外,upcast并downcast禁止.
let sq = System.Convert.ChangeType(n |> float |> sqrt, n.GetType()) :?> ^a 有效,但对我来说似乎很麻烦.
有没有一种方法我忽略了或者我真的必须使用最新版本?因为最后一个也会打破bigint,我经常需要.
小智 4
利用FsControl的技巧,我们可以定义泛型函数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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |