2015-01-25 14 views
12

Załóżmy, że mam proste oświadczenie newtypetworzenia instancji MonadBaseControl dla newtype

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

chcę zrobić Foo wystąpienie MonadBaseControl IO. To powinno być łatwe, ponieważ ReadT Int IO jest już instancją IO MonadBaseControl. Jednak automatyczne wyprowadzenie go przy użyciu GeneralizedNewtypeDeriving nie działa, ponieważ klasa MonadBaseControl ma skojarzony typ.

Jak można napisać instancję IO MonadBaseControl dla Foo? defaultLiftBaseWith i defaultRestoreM powinny być pomocne, ale trochę trudno jest rozszyfrować ich typy.

Odpowiedz

15

Foo nie jest ani "podstawową" monadą, ani monadowym transformatorem. defaultLiftBaseWith nie będzie tu pomocny, ponieważ chcesz, aby instancja dla Foo była identyczna z instancją dla ReaderT Int IO.

Najpierw użyć GND, aby uzyskać nudnych wystąpień:

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

Instancja dla MonadBaseControl IO prostu usuwa newtype, wykorzystuje funkcje z instancji ReaderT, i umieszcza wynik z powrotem w newtype:

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

Zauważ, że jeśli StMnie było skojarzony typ rodziny, można zrobić coś jak

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

type instance StM Foo a = a 
Powiązane problemy