Ich versuche, eine F # -Funktion zu erstellen, die die Summe einer Liste von int
s mit beliebiger Verschachtelung zurückgibt. Dh. es wird für a list<int>
, a list<list<int>>
und a funktionieren list<list<list<list<list<list<int>>>>>>
.
In Haskell würde ich so etwas schreiben wie:
class HasSum a where
getSum :: a -> Integer
instance HasSum Integer where
getSum = id
instance HasSum a => HasSum [a] where
getSum = sum . map getSum
was mich tun lassen würde:
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
Wie kann ich dies in F # erreichen?
getSum (dictList (dictList (..... (dictList dictInt)))) nestedList
wo die Anzahl derdictList
Übereinstimmungen mit der Anzahl[]
in der Art von übereinstimmtnestedList
.Antworten:
AKTUALISIEREN
Ich habe eine einfachere Version gefunden, bei der ein Operator
($)
anstelle eines Mitglieds verwendet wurde. Inspiriert von https://stackoverflow.com/a/7224269/4550898 :Der Rest der Erklärung gilt immer noch und es ist nützlich ...
Ich habe einen Weg gefunden, dies zu ermöglichen:
Führen Sie Ihr Beispiel aus:
Dies basiert auf der Verwendung von SRTPs mit Elementeinschränkungen: Für
static member Sum
die Einschränkung muss der Typ ein Element mit dem Namen an haben, das einSum
zurückgibtint
. Bei der Verwendung von SRTPs müssen generische Funktionen vorhanden seininline
.Das ist nicht der schwierige Teil. Der schwierige Teil ist das "Hinzufügen" eines
Sum
Mitglieds zu einem vorhandenen Typ wieint
undList
was nicht erlaubt ist. Wir können es jedoch einem neuen Typ hinzufügenSumOperations
und in die Einschränkung aufnehmen,(^t or ^a)
wo^t
es immer sein wirdSumOperations
.getSum0
deklariert dieSum
Member-Einschränkung und ruft sie auf.getSum
wirdSumOperations
als erster Typparameter an übergebengetSum0
Die Zeile
static member inline Sum(x : float ) = int x
wurde hinzugefügt, um den Compiler davon zu überzeugen, einen generischen dynamischen Funktionsaufruf zu verwenden und nicht nur standardmäßigstatic member inline Sum(x : int )
beim AufrufList.sumBy
Wie Sie sehen können, ist die Syntax etwas kompliziert, und es war notwendig, einige Macken im Compiler zu umgehen, aber am Ende war es möglich.
Diese Methode kann erweitert werden, um mit Arrays, Tupeln, Optionen usw. oder einer beliebigen Kombination davon zu arbeiten, indem weitere Definitionen hinzugefügt werden zu
SumOperations
:https://dotnetfiddle.net/03rVWT
quelle
Sum
mit einer einfacheren Art getan wird:Sum<int list list list>
,Sum<int list list>
,Sum<int list>
,Sum<int>
.Hier ist die Laufzeitversion, würde mit allen .net-Sammlungen funktionieren. Der Austausch von Compilerfehlern in AMieres 'Antwort gegen Laufzeitausnahmen und AMieres' ist jedoch ebenfalls 36x schneller.
Benchmarks
quelle