2015-06-09 50 views
3

我有點困惑,不知道在哪裏尋找下面的「問題」的信息/解釋(這本身不是一個問題,但更多的情況下,我不明白什麼是錯的幕後):哈斯克爾鏡頭:讓綁定遍歷'

我有StateT一個單子轉換堆棧。在我的函數中的某個時候,我想將我的狀態的一小部分綁定到局部變量中,以便我可以參考它,而不是寫出我感興趣的狀態塊的整個路徑。意思是:

{-# LANGUAGE ScopedTypeVariables #-} 

... 

someFunction :: MyMonad() 
someFunction = do 
    ... 
    let x :: Traversal' MyState MyDataT = myState.clients.ix clientIdx.someData.ix dataIdx 
    ... 

現在,這並不編譯:

Couldn't match type ‘(MyDataT -> f0 MyDataT) 
        -> MyState -> f0 MyState’ 
       with ‘forall (f :: * -> *). 
        Control.Applicative.Applicative f => 
        (MyDataT -> f MyDataT) -> MyState -> f MyState’ 

但如果我搬到這個數據塊的引用到一個函數,那麼一切OK編譯:

someFunction :: MyMonad() 
someFunction = do 
    ... 
    let x = clientData clientIdx dataIdx 
    ... 

    where clientData :: Int -> Int -> Traversal' MyState MyDataT 
     clientData clientIdx dataIdx = myState.clients.ix clientIdx.someData.ix dataIdx 

我我正在尋找某種信息來幫助我瞭解這裏發生了什麼,爲什麼會發生,以便我知道我做錯了什麼。基本上我想擴展我的知識,以更好地理解這個用例。

回答

6

這裏的關鍵是註釋應該在一個單獨的行中。如果我們這樣做了,那麼就GHC而言,我們有一個明確的類型的約束。

someFunction :: MyMonad() 
someFunction = do 
    ... 
    let x :: Traversal' MyState MyDataT 
     x = myState.clients.ix clientIdx.someData.ix dataIdx 
    ... 

什麼你第一次嘗試很少的工作,你打算:

let x :: Traversal' MyState MyDataT = ... 

這是在不顯式類型的綁定;在裏面的註釋是左邊。 GHC在查看右側之前考慮變量的類型,但註釋僅適用於左側,因此GHC只是單獨爲右側推理類型,然後嘗試將其與註釋完全匹配。這使得除了最簡單的非多態情況之外的所有類型檢查都失敗。

把註解內部綁定的正確的方法是以下內容:

let x = ... :: Traversal' MyState MyDataT 

這裏,GHC第一分配一個「可延展的」不確定類型變量x,然後推斷由註釋通知用於右側的類型在那裏,然後將它的類型統一爲x

這仍然是一個沒有顯式類型的綁定,但是如果我們啓用NoMonomorphismRestriction,它的工作原理就可以了,原因在於此SO question中詳述的原因。

+0

非常感謝,這是非常有幫助的 – ksaveljev