Para hacerlo simple, voy a utilizar esta clase de ejemplo artificial (el punto es que tenemos algunos datos costosos derivados de los métodos):memoization y clases de tipos
class HasNumber a where
getNumber :: a -> Integer
getFactors :: a -> [Integer]
getFactors a = factor . getNumber
Por supuesto, podemos hacer implementaciones memoizing de esta clase tales como:
data Foo = Foo {
fooName :: String,
fooNumber :: Integer,
fooFactors :: [Integer]
}
foo :: String -> Integer -> Foo
foo a n = Foo a n (factor n)
instance HasNumber Foo where
getNumber = fooNumber
getFactors = fooFactors
Pero parece un poco feo que se requiere para añadir manualmente un campo 'factores' a cualquier registro que será una instancia de HasNumber
. Siguiente idea:
data WithFactorMemo a = WithFactorMemo {
unWfm :: a,
wfmFactors :: [Integer]
}
withFactorMemo :: HasNumber a => a -> WithFactorMemo a
withFactorMemo a = WithFactorMemo a (getFactors a)
instance HasNumber a => HasNumber (WithFactorMemo a) where
getNumber = getNumber . unWfm
getFactors = wfmFactors
Esto requerirá una gran cantidad de texto modelo para el levantamiento de todas las otras operaciones del original a
en WithFactorMemo a
, sin embargo.
¿Hay alguna solución elegante?
Otra solución que acabo de pensar sería hacer memorando a la función * factor *, aunque esto sería menos práctico si el resultado de 'getNumber' fuera una estructura de datos más grande, y (AFAIK) las entradas nunca recibirían basura (En contraste con las dos soluciones en mi pregunta). – FunctorSalad