Допустимые типы в функциях Numeric.AD
-
11-12-2019 - |
Вопрос
Мне не удалось разобраться в основных сантехнических устройствах типов, задействованных в 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
, или нужна полиморфная версия?
(название вдохновлено этот похожий вопрос)
Решение
я не знаю 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