2015-08-15 103 views
3

我試圖在Haskell中使用automatic differentiation來處理非線性控制問題,但在使其運行時遇到一些問題。我基本上有一個cost函數,應該在初始狀態下對其進行優化。該類型是:Numeric.AD - 類型變量轉義範圍

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

什麼是'Reference'和'Plant'? – Cirdec

+0

與http://stackoverflow.com/a/29393417/414413有關,這兩個問題都與'gradientdecent'的第一個參數的類型有關,它們基本上是相同的答案,但是提出問題的錯誤不同。 – Cirdec

+0

'Reference'和'Plant'是Functors。更具體地說,'Reference'是一個簡單的代數數據類型,'Plant'是來自'netwire'庫的'Wire'的別名。 – bzn

回答

4

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

由於ReferencePlant都是Functor S,您可以通過fmap荷蘭國際集團auto轉換refplantReference aPlant aReference (Reverse s a)Plant (Reverse s a)

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

謝謝,我現在開始工作,雖然它很難看。出於某種原因,'fmap'ing'auto'不起作用,我不得不使用'realToFrac'。我也必須通過兩個參數「fmap」兩次。另外'Plant a'是'netwire'的'Wire s e m a a'的別名,使事情複雜化。現在我將測試我的解決方案併發布答案,如果它有效。 – bzn

+0

如果'Plant a'是別名'Wire s e m a a',那麼'Plant'不是'Functor'。 對於兩個參數兩次使用'fmap'意味着什麼? –