Numeric.AD - переменная типа, выходящая из области видимости
Я пытаюсь использовать автоматическое дифференцирование в Haskell для решения задачи нелинейного управления, но у меня есть некоторые проблемы, заставляющие его работать. У меня в основном есть cost
функция, которая должна быть оптимизирована с учетом исходного состояния. Типы:
data Reference a = Reference a deriving Functor
data Plant a = Plant a deriving Functor
optimize :: (RealFloat a) => Reference a -> Plant a -> [a] -> [[a]]
optimize ref plant initialInputs = gradientDescent (cost ref plant) initialInputs
cost :: (RealFloat a) => Reference a -> Plant a -> [a] -> a
cost = ...
Это приводит к следующему сообщению об ошибке:
Couldn't match expected type `Reference
(Numeric.AD.Internal.Reverse.Reverse s a)'
with actual type `t'
because type variable `s' would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context:
Data.Reflection.Reifies s Numeric.AD.Internal.Reverse.Tape =>
[Numeric.AD.Internal.Reverse.Reverse s a]
-> Numeric.AD.Internal.Reverse.Reverse s a
at test.hs:13:5-50
Relevant bindings include
initialInputs :: [a] (bound at test.hs:12:20)
ref :: t (bound at test.hs:12:10)
optimize :: t -> t1 -> [a] -> [[a]] (bound at test.hs:12:1)
In the first argument of `cost', namely `ref'
In the first argument of `gradientDescent', namely
`(cost ref plant)'
Я даже не уверен, правильно ли я понимаю ошибку. Это, что типы ref
а также plant
нужен доступ к s
, который находится в рамках первого аргумента gradientDescent
?
Можно ли сделать эту работу? При поиске решения я попытался свести проблему к минимальному примеру и обнаружил, что следующее определение выдает похожее сообщение об ошибке:
optimize f inputs = gradientDescent f inputs
Это кажется странным, потому что optimize = gradientDescent
не выдает никакой ошибки.
1 ответ
cost ref plant
имеет тип [a] -> a
где a
та же a
как в подписи к optimize
optimize :: (RealFloat a) => Reference a -> Plant a -> [a] -> [[a]]
^ ^
| ------------
------------------v v
optimize ref plant initialInputs = gradientDescent (cost ref plant) initialInputs
^ ^
----------------------- |
v v---------------
cost :: (RealFloat a) => Reference a -> Plant a -> [a] -> a
cost = ...
Но тип gradientDescent
является
gradientDescent :: (Traversable f, Fractional a, Ord a) =>
(forall s. Reifies s Tape => f (Reverse s a) -> Reverse s a) ->
f a -> [f a]
Первый аргумент gradientDescent
должен быть в состоянии принять (для любого s
) [Reverse s a]
и вернуть Reverse s a
, но cost ref plant
можно только взять [a]
возврат a
,
поскольку Reference
а также Plant
оба Functor
с, вы можете конвертировать ref
а также plant
от Reference a
а также Plant a
в Reference (Reverse s a)
а также Plant (Reverse s a)
от fmap
ИНГ auto
,
optimize :: (RealFloat a) => Reference a -> Plant a -> [a] -> [[a]]
optimize ref plant initialInputs = gradientDescent (cost (fmap auto ref) (fmap auto plant)) initialInputs