У меня мало успехов в том, чтобы разобраться в основной сантехнике типов, включенных в пакет 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]
где grad
имеет тип:
grad
:: (Num a, Traversable f) =>
(forall (s :: * -> *). Mode s => f (AD s a) -> AD s a)
-> f a -> f a
Если я изменю сигнатуру типа ex
на [Double] -> Double
и попробую то же самое, я получу
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
То же самое происходит при замене Double
практически любым конструктором типа типа *
, который создает экземпляр Num
.
Когда Traversable f
является списком, первый аргумент grad
должен иметь тип [AD s a] -> AD s a
для некоторого допустимогоMode
-например,Reverse
. Но очевидно, что пользователь grad
не должен иметь дело сAD
конструктор или Mode
напрямую. Заглянув в эти внутренности, я немного сбит с толку; в частности, я не могу понять разницу между использованием Num a => [a] -> a
и [Double] -> Double
по типу/типу.
Почему сигнатура типа [Double] -> Double
вызывает проблемы с grad
? И с точки зрения использования старой простой библиотеки :, есть ли способ использовать [Double] -> Double
версию ex
или необходима полиморфная версия?
(название, вдохновленное похожим вопросом)