Допустимые типы в функциях Numeric.AD
Я с небольшим успехом оборачиваюсь вокруг основного водопровода типов, вовлеченных в 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
или нужна полиморфная версия?
(название вдохновлено этим похожим вопросом)
1 ответ
Я не знаю ad
библиотека, но так как grad
ожидает функцию типа [AD s a] -> AD s a
в качестве первого параметра вы не можете ожидать, что сможете передать ему функцию типа [Double] -> Double
, поскольку Double
а также AD
это совершенно разные типы.
Общая функция с Num
ограничение работает, потому что AD
сам по себе также является примером Num
поэтому в вашем рабочем примере ex
специализируется на что-то вроде
ex :: (Mode s, Fractional a) => [AD s a] -> AD s a
Если вы хотите специализироваться ex
для расчетов с использованием Doubles необходимо указать такую подпись, как
ex :: Mode s => [AD s Double] -> AD s Double