2015-01-25 7 views
12

Supponiamo che io sono semplice dichiarazione Newtypecreando esempio MonadBaseControl per Newtype

newtype Foo a = Foo { unFoo :: ReaderT Int IO a } 

voglio fare istanza Foo di MonadBaseControl IO. Dovrebbe essere facile, dato che ReaderT Int IO è già un'istanza di MonadBaseControl IO. Tuttavia, la derivazione automatica utilizzando GeneralizedNewtypeDeriving non funziona, poiché la classe MonadBaseControl ha un tipo associato.

Come si può scrivere un'istanza di MonadBaseControl IO per Foo? defaultLiftBaseWith e defaultRestoreM dovrebbero essere utili, ma è un po 'difficile decifrare i loro tipi.

risposta

15

Foo non è né una "base" monade né un trasformatore monade. defaultLiftBaseWith non sarà utile qui, dal momento che si desidera che l'istanza per sia identica a quella per ReaderT Int IO.

In primo luogo, utilizzare GND per ottenere le istanze noiosi:

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

import Control.Monad.Trans.Control 
import Control.Monad.Base 
import Control.Monad.Reader 
import Control.Applicative 

newtype Foo a = Foo { unFoo :: ReaderT Int IO a } 
    deriving (Monad, Applicative, Functor, MonadBase IO) 

L'istanza per MonadBaseControl IO solo rimuove i newtype, utilizza le funzioni dall'istanza ReaderT, e pone il risultato torna in newtype:

instance MonadBaseControl IO Foo where 
    type StM Foo a = a 
    liftBaseWith f = Foo $ liftBaseWith $ \q -> f (q . unFoo) 
    restoreM = Foo . restoreM 

Nota che se StMnon era un tipo di famiglia associata, si potrebbe fare qualcosa di simile

0.123.
newtype Foo a = Foo { unFoo :: ReaderT Int IO a } 
    deriving (Monad, Applicative, Functor, MonadBase IO, MonadBaseControl IO) 

type instance StM Foo a = a