2016-04-25 77 views
2

這個問題顯然與討論的問題herehere有關。不幸的是,我的要求與這些問題略有不同,所給出的答案不適用於我。我也不太明白爲什麼runST未能在這些情況下輸入檢查,這沒有幫助。在變壓器堆棧中展開STT monad?

我的問題是這樣的,我有一個代碼段使用一個單子堆棧,或者更確切地說,一個單子:

import Control.Monad.Except 
type KErr a = Except KindError a 

的另一段代碼需要與此一個包裝這個STT monad內集成:

type RunM s a = STT s (Except KindError) a 

在這些部分之間的接口處,我顯然需要包裝和解開外層。我有以下功能在KErr工作 - >RunM方向:

kerrToRun :: KErr a -> RunM s a 
kerrToRun e = either throwError return $ runExcept e 

,但由於某種原因,我只是不能反過來鍵入查詢:

runToKErr :: RunM s a -> KErr a 
runToKErr r = runST r 

我假設RunM的內部monad具有與KErr相同的結構,我可以在解開STT圖層後返回它,但我似乎無法獲得如此遠的效果,因爲runST抱怨關於其類型參數:

src/KindLang/Runtime/Eval.hs:18:21: 
    Couldn't match type ‘s’ with ‘s1’ 
     ‘s’ is a rigid type variable bound by 
      the type signature for runToKErr :: RunM s a -> KErr a 
      at src/KindLang/Runtime/Eval.hs:17:14 
     ‘s1’ is a rigid type variable bound by 
      a type expected by the context: 
      STT s1 (ExceptT KindError Data.Functor.Identity.Identity) a 
      at src/KindLang/Runtime/Eval.hs:18:15 
    Expected type: STT 
        s1 (ExceptT KindError Data.Functor.Identity.Identity) a 
     Actual type: RunM s a 

我也試過:

runToKErr r = either throwError return $ runExcept $ runST r 

,以更強烈隔離其預期收益類型runST,在那是問題的原因的情況下,但結果是一樣的。

這個s1類型從哪裏來,我如何說服ghc它與s是同一類型?

回答

5

(約ST s a下面的談判,但只適用於同STT s m a;我剛剛避免談論低於變壓器版本的不必要的複雜)

您所看到的問題是,runST已鍵入(forall s. ST s a) -> a到從外部,純淨的世界隔離計算的任何潛在的影響(STRef-變化)。所有ST計算,STRef s等被標記的s幻象類型的全部點是跟蹤它們屬於哪個「ST」域;並且runST的類型確保域之間無法傳遞任何內容。

您可以通過強制執行相同不變寫runToKErr

{-# language Rank2Types #-} 

runToKErr :: (forall s. RunM s a) -> KErr a 
runToKErr = runST 

(當然,你可能會進一步實現降低這個限制是你希望寫程序太強大了道路;在這一點上你我需要失去希望,對不起,我的意思是你需要重新設計你的程序。)

至於錯誤信息,你不能「說服式檢查器s1s是同一類型」的原因是因爲如果我傳給你的ST s asa一個給定的選擇,那就是不同於給你的東西,它允許你選擇你自己的s。 GHC選擇s1(一個Skolemized變量)作爲s,所以試圖統一ST s aST s1 a