我正在尝试在Haskell中使用automatic differentiation来解决非线性控制问题,但是在使其工作时遇到了一些问题。我基本上有一个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)'

我什至不确定我是否正确理解该错误。是refplant的类型需要访问s,它在gradientDescent的第一个参数的范围之内?

有可能使这项工作吗?在寻找解决方案时,我尝试将问题简化为最小示例,发现以下定义会产生类似的错误消息:
optimize f inputs = gradientDescent f inputs

这似乎很奇怪,因为optimize = gradientDescent不会产生任何错误。

最佳答案

cost ref plant具有[a] -> a类型,其中aa签名中的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

由于ReferencePlant都是Functor,因此可以通过ref plant Reference aPlant aReference (Reverse s a)Plant (Reverse s a)转换为fmapauto
optimize :: (RealFloat a) => Reference a -> Plant a -> [a] -> [[a]]
optimize ref plant initialInputs = gradientDescent (cost (fmap auto ref) (fmap auto plant)) initialInputs

关于haskell - Numeric.AD-类型变量,转义其范围,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32027302/

10-10 10:01