MISE À JOUR
J'ai trouvé une version plus simple utilisant un opérateur ($)au lieu d'un membre. Inspiré par https://stackoverflow.com/a/7224269/4550898 :
type SumOperations = SumOperations
let inline getSum b = SumOperations $ b // <-- puting this here avoids defaulting to int
type SumOperations with
static member inline ($) (SumOperations, x : int ) = x
static member inline ($) (SumOperations, xl : _ list) = xl |> List.sumBy getSum
Le reste de l'explication s'applique toujours et c'est utile ...
J'ai trouvé un moyen de le rendre possible:
let inline getSum0< ^t, ^a when (^t or ^a) : (static member Sum : ^a -> int)> a : int =
((^t or ^a) : (static member Sum : ^a -> int) a)
type SumOperations =
static member inline Sum( x : float ) = int x
static member inline Sum( x : int ) = x
static member inline Sum(lx : _ list) = lx |> List.sumBy getSum0<SumOperations, _>
let inline getSum x = getSum0<SumOperations, _> x
2 |> getSum |> printfn "%d" // = 2
[ 2 ; 1 ] |> getSum |> printfn "%d" // = 3
[[2; 3] ; [4; 5] ] |> getSum |> printfn "%d" // = 14
Exécuter votre exemple:
let list v = List.replicate 6 v
1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176
Ceci est basé sur l'utilisation de SRTP avec des contraintes de membre:, static member Sumla contrainte requiert que le type ait un membre appelé Sum
qui renvoie un int. Lors de l'utilisation de SRTP, les fonctions génériques doivent l'être inline.
Ce n'est pas la partie difficile. La partie difficile est « ajoutant » Summembre à un type existant comme intet ce Listqui est interdit. Mais, nous pouvons l'ajouter à un nouveau type SumOperationset l'inclure dans la contrainte (^t or ^a)
où ^tva toujours être SumOperations.
getSum0déclare la Sumcontrainte de membre et l'invoque.
getSum passe SumOperationscomme premier paramètre de type àgetSum0
La ligne a static member inline Sum(x : float ) = int xété ajoutée pour convaincre le compilateur d'utiliser un appel de fonction dynamique générique et pas seulement par défaut static member inline Sum(x : int )lors de l'appelList.sumBy
Comme vous pouvez le voir, c'est un peu compliqué, la syntaxe est complexe et il était nécessaire de contourner certaines bizarreries sur le compilateur mais à la fin c'était possible.
Cette méthode peut être étendue pour fonctionner avec des tableaux, des tuples, des options, etc. ou toute combinaison de ceux-ci en ajoutant plus de définitions à SumOperations:
type SumOperations with
static member inline ($) (SumOperations, lx : _ [] ) = lx |> Array.sumBy getSum
static member inline ($) (SumOperations, a : ^a * ^b ) = match a with a, b -> getSum a + getSum b
static member inline ($) (SumOperations, ox : _ option) = ox |> Option.map getSum |> Option.defaultValue 0
(Some 3, [| 2 ; 1 |]) |> getSum |> printfn "%d" // = 6
https://dotnetfiddle.net/03rVWT
getSum (dictList (dictList (..... (dictList dictInt)))) nestedListoù le nombre dedictListcorrespond au nombre de[]dans le type denestedList.