AKTUALISIEREN
Ich habe eine einfachere Version gefunden, bei der ein Operator ($)
anstelle eines Mitglieds verwendet wurde. Inspiriert von 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
Der Rest der Erklärung gilt immer noch und es ist nützlich ...
Ich habe einen Weg gefunden, dies zu ermöglichen:
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
Führen Sie Ihr Beispiel aus:
let list v = List.replicate 6 v
1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176
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 ein Sum
zurückgibt int
. Bei der Verwendung von SRTPs müssen generische Funktionen vorhanden sein inline
.
Das ist nicht der schwierige Teil. Der schwierige Teil ist das "Hinzufügen" eines Sum
Mitglieds zu einem vorhandenen Typ wie int
und List
was nicht erlaubt ist. Wir können es jedoch einem neuen Typ hinzufügen SumOperations
und in die Einschränkung aufnehmen, (^t or ^a)
wo ^t
es immer sein wird SumOperations
.
getSum0
deklariert die Sum
Member-Einschränkung und ruft sie auf.
getSum
wird SumOperations
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äßig static 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
:
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)))) nestedList
wo die Anzahl derdictList
Übereinstimmungen mit der Anzahl[]
in der Art von übereinstimmtnestedList
.