Обобщенное получение Newtype

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)

person Bob    schedule 05.09.2014    source источник


Ответы (1)


Вы не можете иметь тип с двумя экземплярами для 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.

person bheklilr    schedule 05.09.2014