2014-09-05 38 views
6

Haskell中可以推導出實例MonadState s以下但不T1T2然而,這是一個非常相似的類型。在哪種方式下,我應該修改T2的代碼,以便MonadState s的實例可以自動派生?廣義NEWTYPE派生

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

import Control.Monad.Reader 
import Control.Monad.State 

newtype T1 r s a = 
    T1 { runT1 :: ReaderT r (State s) a } 
    deriving (Monad, MonadReader r, MonadState s) 

newtype T2 r s a = 
    T2 { runT2 :: StateT r (State s) a } 
    deriving (Monad, MonadState r, MonadState s) 

回答

7

對於MonadState,不能有一個類型有兩個實例。這是因爲MonadState被定義爲

class Monad m => MonadState s m | m -> s where 
    get :: m s 
    set :: s -> m() 
    state :: (s -> (a, s)) -> m a 

的關鍵部分是| m -> s。這需要擴展FunctionalDependencies,並說明任何m,我們自動知道相關s。這意味着對於任何給定的m,只有一個選擇s有效。因此,除非r ~ s,否則MonadState r mMonadState s m都不能使用。如果r ~ s,那麼編譯器將如何知道它應用於哪個底層monad?在這種情況下,我認爲您還會發現,如果您創建了getput函數,並具有後綴以指示哪些函數(如getInnersetInnergetOuter,setOuter),則會更容易理解和使用代碼。