Bardzo często podczas pisania kodu rodzajowe w F # wpadnę sytuacji podobnej do tego (wiem, że to zupełnie nieefektywne, tylko dla celów demonstracyjnych):Jak mogę odrzucić powrót do typu, który wcześniej miał wartość?
let isPrime n =
let sq = n |> float |> sqrt |> int
{2..sq} |> Seq.forall (fun d -> n % d <> 0)
Dla wielu problemów można używać statically resolved types i uzyskać nawet zwiększenie wydajności dzięki inline.
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)
Powyższy kod nie zostanie skompilowany, ponieważ górny limit sekwencji jest zmiennoprzecinkowy. Nongenerically, mógłbym właśnie odesłać z powrotem do int
na przykład.
Ale kompilator nie pozwoli mi użyć dowolnego z nich:
let sq = n |> float |> sqrt :> ^a
let sq = n |> float |> sqrt :?> ^a
a te dwa prowadzą do InvalidCastException
:
let sq = n |> float |> sqrt |> box |> :?> ^a
let sq = n |> float |> sqrt |> box |> unbox
Również upcast
i downcast
są zabronione.
let sq = System.Convert.ChangeType(n |> float |> sqrt, n.GetType()) :?> ^a
działa, ale wydaje się bardzo uciążliwe dla mnie.
Czy istnieje sposób, który przeoczyłem lub czy muszę używać ostatniej wersji? Ponieważ ostatnia z nich również pęknie na bigint
, której potrzebuję dość często.
Zrobiłem trochę skrzypce i najmilszym rozwiązaniem, jakie wymyśliłem, było zmodyfikowanie głównej biblioteki. Jeśli nie zależy Ci szczególnie na wydajności, zawsze możesz zwiększyć liczbę, dodając moce dwóch. –
Dlaczego musisz przesyłać do 'float' przed wywołaniem' sqrt'? – Daniel
@Daniel, ponieważ nie możesz (na przykład) przekazać int do sqrt: 'Typ 'int' nie obsługuje operatora 'Sqrt'' – phoog