En plus de kvb de la technique à l'aide de Littéraux Numériques (Brian le lien), j'ai eu beaucoup de succès en utilisant une autre technique qui peut donner de meilleurs déduit le type de construction des signatures et peut également être utilisé pour créer précalculées type de fonctions spécifiques pour améliorer les performances ainsi que le contrôle des prises en charge les types numériques (puisque vous voudrez souvent à l'appui de tous les types intégraux, mais pas rationnelle types, par exemple): F# Membre Statique Type de Contraintes.
Suite à la discussion Daniel et moi avons été d'avoir sur le type inféré signatures produites par les différentes techniques, en voici un aperçu:
NumericLiteralG Technique
module NumericLiteralG =
let inline FromZero() = LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromInt32 (n:int) =
let one = FromOne()
let zero = FromZero()
let n_incr = if n > 0 then 1 else -1
let g_incr = if n > 0 then one else (zero - one)
let rec loop i g =
if i = n then g
else loop (i + n_incr) (g + g_incr)
loop 0 zero
Crossfoot sans ajout d'annotations de type:
let inline crossfoot1 n =
let rec compute n =
if n = 0G then 0G
else n % 10G + compute (n / 10G)
compute n
val inline crossfoot1 :
^a -> ^e
when ( ^a or ^b) : (static member ( % ) : ^a * ^b -> ^d) and
^a : (static member get_Zero : -> ^a) and
( ^a or ^f) : (static member ( / ) : ^a * ^f -> ^a) and
^a : equality and ^b : (static member get_Zero : -> ^b) and
( ^b or ^c) : (static member ( - ) : ^b * ^c -> ^c) and
( ^b or ^c) : (static member ( + ) : ^b * ^c -> ^b) and
^c : (static member get_One : -> ^c) and
( ^d or ^e) : (static member ( + ) : ^d * ^e -> ^e) and
^e : (static member get_Zero : -> ^e) and
^f : (static member get_Zero : -> ^f) and
( ^f or ^g) : (static member ( - ) : ^f * ^g -> ^g) and
( ^f or ^g) : (static member ( + ) : ^f * ^g -> ^f) and
^g : (static member get_One : -> ^g)
Crossfoot ajoutant quelques annotations de type:
let inline crossfoot2 (n:^a) : ^a =
let (zero:^a) = 0G
let (ten:^a) = 10G
let rec compute (n:^a) =
if n = zero then zero
else ((n % ten):^a) + compute (n / ten)
compute n
val inline crossfoot2 :
^a -> ^a
when ^a : (static member get_Zero : -> ^a) and
( ^a or ^a0) : (static member ( - ) : ^a * ^a0 -> ^a0) and
( ^a or ^a0) : (static member ( + ) : ^a * ^a0 -> ^a) and
^a : equality and ^a : (static member ( + ) : ^a * ^a -> ^a) and
^a : (static member ( % ) : ^a * ^a -> ^a) and
^a : (static member ( / ) : ^a * ^a -> ^a) and
^a0 : (static member get_One : -> ^a0)
Enregistrement De Type Technique
module LP =
let inline zero_of (target:'a) : 'a = LanguagePrimitives.GenericZero<'a>
let inline one_of (target:'a) : 'a = LanguagePrimitives.GenericOne<'a>
let inline two_of (target:'a) : 'a = one_of(target) + one_of(target)
let inline three_of (target:'a) : 'a = two_of(target) + one_of(target)
let inline negone_of (target:'a) : 'a = zero_of(target) - one_of(target)
let inline any_of (target:'a) (x:int) : 'a =
let one:'a = one_of target
let zero:'a = zero_of target
let xu = if x > 0 then 1 else -1
let gu:'a = if x > 0 then one else zero-one
let rec get i g =
if i = x then g
else get (i+xu) (g+gu)
get 0 zero
type G<'a> = {
negone:'a
zero:'a
one:'a
two:'a
three:'a
any: int -> 'a
}
let inline G_of (target:'a) : (G<'a>) = {
zero = zero_of target
one = one_of target
two = two_of target
three = three_of target
negone = negone_of target
any = any_of target
}
open LP
Crossfoot, pas d'annotations nécessaires pour nice déduit de la signature:
let inline crossfoot3 n =
let g = G_of n
let ten = g.any 10
let rec compute n =
if n = g.zero then g.zero
else n % ten + compute (n / ten)
compute n
val inline crossfoot3 :
^a -> ^a
when ^a : (static member ( % ) : ^a * ^a -> ^b) and
( ^b or ^a) : (static member ( + ) : ^b * ^a -> ^a) and
^a : (static member get_Zero : -> ^a) and
^a : (static member get_One : -> ^a) and
^a : (static member ( + ) : ^a * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) and ^a : equality and
^a : (static member ( / ) : ^a * ^a -> ^a)
Crossfoot, pas d'annotations, accepte précalculées instances de G:
let inline crossfootG g ten n =
let rec compute n =
if n = g.zero then g.zero
else n % ten + compute (n / ten)
compute n
val inline crossfootG :
G< ^a> -> ^b -> ^a -> ^a
when ( ^a or ^b) : (static member ( % ) : ^a * ^b -> ^c) and
( ^c or ^a) : (static member ( + ) : ^c * ^a -> ^a) and
( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^a) and
^a : equality
J'utilise le ci-dessus dans la pratique, car alors je peux faire précalculées type des versions spécifiques qui ne souffrent pas de la performance coût de Générique LanguagePrimitives:
let gn = G_of 1 //int32
let gL = G_of 1L //int64
let gI = G_of 1I //bigint
let gD = G_of 1.0 //double
let gS = G_of 1.0f //single
let gM = G_of 1.0m //decimal
let crossfootn = crossfootG gn (gn.any 10)
let crossfootL = crossfootG gL (gL.any 10)
let crossfootI = crossfootG gI (gI.any 10)
let crossfootD = crossfootG gD (gD.any 10)
let crossfootS = crossfootG gS (gS.any 10)
let crossfootM = crossfootG gM (gM.any 10)