2014-09-05 13 views
6

Haskell può derivare l'istanza per MonadState s in T1 in basso ma non in T2 che tuttavia è un tipo molto simile. In che modo dovrei modificare il codice per T2 in modo che l'istanza per MonadState s possa essere derivata automaticamente?Derivato Newtype generalizzato

{-# 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) 

risposta

7

Non si può avere un tipo hanno due istanze per MonadState. Questo perché MonadState è definito come

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

La parte fondamentale è la | m -> s. Ciò richiede l'estensione FunctionalDependencies e afferma che per qualsiasi m, conosciamo automaticamente lo s associato. Ciò significa che per qualsiasi dato m, può essere solo una scelta per s valida. Quindi non puoi farlo funzionare sia per MonadState r m e MonadState s m a meno che non sia r ~ s. Se r ~ s, in che modo il compilatore dovrebbe sapere a quale monade sottostante si deve applicare? In questo caso, riterrò anche che sarà molto più facile capire e lavorare con il codice se crei le funzioni get e put con suffissi per indicare quali, come getInner, setInner e getOuter, setOuter.

Problemi correlati