Очень часто при написании родового кода в F # я сталкиваюсь с ситуацией, подобной этой (я знаю, что это довольно неэффективно, просто для демонстрационных целей):
let isPrime n =
let sq = n |> float |> sqrt |> int
{2..sq} |> Seq.forall (fun d -> n % d <> 0)
Для многих проблем я могу использовать статически разрешенные типы и получить даже повышение производительности из-за 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)
Приведенный выше код не будет компилироваться из-за того, что верхний предел последовательности является поплавком. В некотором роде, я мог бы просто вернуться к int
, например.
Но компилятор не позволит мне использовать какие-либо из них:
-
let sq = n |> float |> sqrt :> ^a
-
let sq = n |> float |> sqrt :?> ^a
и эти два ведут к InvalidCastException
:
-
let sq = n |> float |> sqrt |> box |> :?> ^a
-
let sq = n |> float |> sqrt |> box |> unbox
Кроме того, upcast
и downcast
запрещены.
let sq = System.Convert.ChangeType(n |> float |> sqrt, n.GetType()) :?> ^a
работает, но мне кажется очень громоздким.
Есть ли способ, который я забыл или мне действительно нужно использовать последнюю версию? Потому что последний будет разбиваться на bigint
, что мне нужно довольно часто.