Estoy teniendo poco éxito en mi trabajo con la fontanería básica de los tipos implicados en el paquete ad
. Por ejemplo, la siguiente funciona perfectamente:Tipos aceptables en las funciones de Numeric.AD
import Numeric.AD
ex :: Num a => [a] -> a
ex [x, y] = x + 2*y
> grad ex [1.0, 1.0]
[1.0, 2.0]
donde grad
tiene el tipo:
grad
:: (Num a, Traversable f) =>
(forall (s :: * -> *). Mode s => f (AD s a) -> AD s a)
-> f a -> f a
Si cambio de la firma tipo de ex
-[Double] -> Double
y tratar de lo mismo, me sale
Couldn't match expected type `AD s a0' with actual type `Double'
Expected type: f0 (AD s a0) -> AD s a0
Actual type: [Double] -> Double
El mismo comportamiento se produce al reemplazar Double
con aparentemente cualquier tipo constructor con tipo *
que crea instancias Num
.
Cuando el Traversable f
es una lista, el primer argumento de grad
debe tener un tipo [AD s a] -> AD s a
por alguna aceptable Mode
- por ejemplo, Reverse
. Pero claramente el usuario de grad
no tiene que tratar directamente con el constructor AD
o el Mode
. Echar un vistazo a estas partes internas me ha dejado un poco confundido; específicamente, no puedo seguir el rastro de tipo/tipo a la diferencia entre usar Num a => [a] -> a
y [Double] -> Double
.
¿Por qué la firma tipo [Double] -> Double
causa problemas con grad
? Y en términos del uso simple de la biblioteca anterior: ¿hay alguna forma de utilizar la versión [Double] -> Double
de ex
, o es una versión polimórfica necesaria?
(título inspirado por this similar question)
Ahhhh ok, entonces 'AD' es una instancia de' Num'. No lo noté en la lista de instancias, pero ahora lo veo. – jtobin
Además, si tiene algunas constantes en Dobles, por ejemplo, en otras estructuras de datos, es posible que necesite usar Numeric.AD.Types.lift o los otros combinadores en Modo para que interactúen con los argumentos dobles y el resultado de su AD. . –