Estoy tratando de crear una función F # que devolverá la suma de una lista de int
s de anidamiento arbitrario. Es decir. funcionará para a list<int>
, a list<list<int>>
y a list<list<list<list<list<list<int>>>>>>
.
En Haskell escribiría 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
lo que me dejaría hacer:
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
¿Cómo puedo lograr esto en F #?
getSum (dictList (dictList (..... (dictList dictInt)))) nestedList
el número dedictList
coincidencias con el número del[]
tipo denestedList
.Respuestas:
ACTUALIZAR
Encontré una versión más simple usando un operador en
($)
lugar de un miembro. Inspirado en https://stackoverflow.com/a/7224269/4550898 :El resto de la explicación aún se aplica y es útil ...
Encontré una manera de hacerlo posible:
Ejecutando su ejemplo:
Esto se basa en el uso de SRTP con restricciones de miembros:
static member Sum
la restricción requiere que el tipo tenga un miembro llamadoSum
que devuelva unint
. Cuando se usan SRTP, las funciones genéricas deben serinline
.Esa no es la parte difícil. La parte difícil es "agregar"
Sum
miembros a un tipo existente comoint
yList
que no está permitido. Pero, podemos agregarlo a un nuevo tipoSumOperations
e incluir en la restricción(^t or ^a)
dónde^t
siempre va a estarSumOperations
.getSum0
declara laSum
restricción de miembro y la invoca.getSum
pasaSumOperations
como el primer parámetro de tipo agetSum0
La línea
static member inline Sum(x : float ) = int x
se agregó para convencer al compilador de que use una llamada de función dinámica genérica y no solo por defectostatic member inline Sum(x : int )
al llamarList.sumBy
Como puede ver es un poco complicado, la sintaxis es compleja y fue necesario solucionar algunas peculiaridades en el compilador, pero al final fue posible.
Este método se puede extender para trabajar con matrices, tuplas, opciones, etc. o cualquier combinación de ellas agregando más definiciones a
SumOperations
:https://dotnetfiddle.net/03rVWT
fuente
Sum
se realiza con un tipo más simple:Sum<int list list list>
,Sum<int list list>
,Sum<int list>
,Sum<int>
.Aquí está la versión en tiempo de ejecución, funcionaría con todas las colecciones .net. Sin embargo, intercambia errores del compilador en la respuesta de AMieres por excepciones de tiempo de ejecución y AMieres también es 36 veces más rápido.
Puntos de referencia
fuente