2014-09-05 4 views
6

Haskell может выдавать экземпляр для MonadState s в T1 ниже, но не в T2, который, однако, очень похож на тип. Каким образом я должен изменить код для T2, чтобы можно было автоматически получить экземпляр для MonadState s?Генератор обобщенного нового типа

{-# 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, который действителен. Таким образом, вы не можете заставить его работать как для MonadState r m, так и для MonadState s m, за исключением случаев, когда r ~ s. Если r ~ s, то как компилятор узнает, к какой базовой монаде он применим? В этом случае, я думаю, вы также обнаружите, что будет намного легче понять и работать с кодом, если вы создадите функции get и put, которые имеют суффиксы, чтобы указать, какие, например getInner, setInner и getOuter, setOuter.