Numeric.AD - 类型变量转义其范围

时间:2015-08-15 17:23:37

标签: haskell automatic-differentiation

我正在尝试在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不会产生任何错误。

1 个答案:

答案 0 :(得分:4)

cost ref plant的{​​{1}}类型[a] -> aa

的签名中的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,但{ {1}}只能cost ref plant返回[a]

由于aReference都是Plant,您可以从Functorref转换plantReference a通过Plant a auto Reference (Reverse s a)Plant (Reverse s a)fmap

optimize :: (RealFloat a) => Reference a -> Plant a -> [a] -> [[a]]
optimize ref plant initialInputs = gradientDescent (cost (fmap auto ref) (fmap auto plant)) initialInputs