Próbuję utworzyć funkcję F #, która zwróci sumę listy int
s dowolnego zagnieżdżenia. To znaczy. będzie działać dla a list<int>
, a list<list<int>>
i a list<list<list<list<list<list<int>>>>>>
.
W Haskell napisałbym coś takiego:
class HasSum a where
getSum :: a -> Integer
instance HasSum Integer where
getSum = id
instance HasSum a => HasSum [a] where
getSum = sum . map getSum
co pozwoliłoby mi zrobić:
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
Jak mogę to osiągnąć w F #?
getSum (dictList (dictList (..... (dictList dictInt)))) nestedList
którym liczbadictList
pasuje do liczby[]
w typienestedList
.Odpowiedzi:
AKTUALIZACJA
Znalazłem prostszą wersję, używając operatora
($)
zamiast członka. Inspirowany https://stackoverflow.com/a/7224269/4550898 :Reszta wyjaśnienia nadal obowiązuje i jest przydatna ...
Znalazłem sposób, aby to umożliwić:
Uruchamianie Twojego przykładu:
Opiera się to na stosowaniu SRTP z ograniczeniami elementu:
static member Sum
ograniczenie wymaga, aby typ miał wywoływany elementSum
zwracający wartośćint
. Podczas korzystania z SRTP muszą to być funkcje ogólneinline
.To nie jest trudna część. Trudną częścią jest „dodawanie”
Sum
elementu do istniejącego typu, takiego jakint
iList
który jest niedozwolony. Ale możemy dodać go do nowego typuSumOperations
i uwzględnić w ograniczeniu,(^t or ^a)
gdzie^t
zawsze będzieSumOperations
.getSum0
deklarujeSum
ograniczenie członka i wywołuje je.getSum
przechodziSumOperations
jako parametr pierwszego typu dogetSum0
Linia
static member inline Sum(x : float ) = int x
została dodana, aby przekonać kompilator do używania ogólnego dynamicznego wywołania funkcji, a nie tylko domyślnegostatic member inline Sum(x : int )
podczas wywoływaniaList.sumBy
Jak widać jest nieco skomplikowana, składnia jest złożona i trzeba było obejść pewne dziwactwa na kompilatorze, ale ostatecznie było to możliwe.
Metodę tę można rozszerzyć do pracy z tablicami, krotkami, opcjami itp. Lub dowolną ich kombinacją, dodając więcej definicji do
SumOperations
:https://dotnetfiddle.net/03rVWT
źródło
Sum
odbywa się prostszy typ:Sum<int list list list>
,Sum<int list list>
,Sum<int list>
,Sum<int>
.Oto wersja środowiska wykonawczego, działająca ze wszystkimi kolekcjami .net. Wymienia jednak błędy kompilatora w odpowiedzi AMieres na wyjątki czasu wykonywania i AMieres również jest 36 razy szybszy.
Benchmarki
źródło