J'essaie de créer une fonction F # qui renverra la somme d'une liste de int
s d'imbrication arbitraire. C'est à dire. cela fonctionnera pour a list<int>
, a list<list<int>>
et a list<list<list<list<list<list<int>>>>>>
.
En Haskell, j'écrirais quelque chose comme:
class HasSum a where
getSum :: a -> Integer
instance HasSum Integer where
getSum = id
instance HasSum a => HasSum [a] where
getSum = sum . map getSum
ce qui me permettrait de faire:
list :: a -> [a]
list = replicate 6
nestedList :: [[[[[[[[[[Integer]]]]]]]]]]
nestedList =
list $ list $ list $ list $ list $
list $ list $ list $ list $ list (1 :: Integer)
sumNestedList :: Integer
sumNestedList = getSum nestedList
Comment puis-je y parvenir en F #?
getSum (dictList (dictList (..... (dictList dictInt)))) nestedList
où le nombre dedictList
correspond au nombre de[]
dans le type denestedList
.Réponses:
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 :Le reste de l'explication s'applique toujours et c'est utile ...
J'ai trouvé un moyen de le rendre possible:
Exécuter votre exemple:
Ceci est basé sur l'utilisation de SRTP avec des contraintes de membre:,
static member Sum
la contrainte requiert que le type ait un membre appeléSum
qui renvoie unint
. Lors de l'utilisation de SRTP, les fonctions génériques doivent l'êtreinline
.Ce n'est pas la partie difficile. La partie difficile est « ajoutant »
Sum
membre à un type existant commeint
et ceList
qui est interdit. Mais, nous pouvons l'ajouter à un nouveau typeSumOperations
et l'inclure dans la contrainte(^t or ^a)
où^t
va toujours êtreSumOperations
.getSum0
déclare laSum
contrainte de membre et l'invoque.getSum
passeSumOperations
comme 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éfautstatic 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
:https://dotnetfiddle.net/03rVWT
la source
Sum
se fait avec un type plus simple:Sum<int list list list>
,Sum<int list list>
,Sum<int list>
,Sum<int>
.Voici la version d'exécution, qui fonctionnerait avec toutes les collections .net. Cependant, échange les erreurs du compilateur dans la réponse d' AMières pour les exceptions d'exécution et AMières est 36 fois plus rapide également.
Repères
la source