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
Другие вопросы по тегам