Estou tentando criar uma função F # que retornará a soma de uma lista de int
s de aninhamento arbitrário. Ou seja. funcionará para a list<int>
, a list<list<int>>
e a list<list<list<list<list<list<int>>>>>>
.
Em Haskell, eu escreveria algo como:
class HasSum a where
getSum :: a -> Integer
instance HasSum Integer where
getSum = id
instance HasSum a => HasSum [a] where
getSum = sum . map getSum
o que me deixaria fazer:
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
Como posso conseguir isso em F #?
getSum (dictList (dictList (..... (dictList dictInt)))) nestedList
onde o número dedictList
corresponde ao número de[]
no tipo denestedList
.Respostas:
ATUALIZAR
Encontrei uma versão mais simples usando um operador em
($)
vez de um membro. Inspirado em https://stackoverflow.com/a/7224269/4550898 :O restante da explicação ainda se aplica e é útil ...
Eu encontrei uma maneira de tornar isso possível:
Executando seu exemplo:
Isso se baseia no uso de SRTPs com restrições de membro:,
static member Sum
a restrição requer que o tipo tenha um membro chamadoSum
que retorne umint
. Ao usar SRTPs, funções genéricas precisam serinline
.Essa não é a parte difícil. A parte difícil é "adicionar"
Sum
membro a um tipo existente comoint
eList
que não é permitido. Porém, podemos adicioná-lo a um novo tipoSumOperations
e incluir na restrição(^t or ^a)
onde^t
sempre estaráSumOperations
.getSum0
declara aSum
restrição de membro e a invoca.getSum
passaSumOperations
como o primeiro parâmetro de tipo paragetSum0
A linha
static member inline Sum(x : float ) = int x
foi adicionada para convencer o compilador a usar uma chamada de função dinâmica genérica e não apenas o padrão aostatic member inline Sum(x : int )
chamarList.sumBy
Como você pode ver, é um pouco complicado, a sintaxe é complexa e foi necessário contornar algumas peculiaridades no compilador, mas no final foi possível.
Esse método pode ser estendido para trabalhar com matrizes, tuplas, opções etc. ou qualquer combinação delas, adicionando mais definições a
SumOperations
:https://dotnetfiddle.net/03rVWT
fonte
Sum
é feito com um tipo mais simples:Sum<int list list list>
,Sum<int list list>
,Sum<int list>
,Sum<int>
.Aqui está a versão em tempo de execução, funcionaria com todas as coleções .net. No entanto, as trocas de erros do compilador na resposta do AMieres para exceções de tempo de execução e no AMieres também são 36x mais rápidas.
Benchmarks
fonte