2011-09-14 14 views
5

Eğer soru biraz önemsiz görünüyorsa üzgünüm ... bu benim için değil.Bir trafo olarak monad kompozisyonunun soyutlanması

type SB i a = ReaderT (AlgRO i) (State (AlgState i)) a 

de, bir iyi huylu monad: mutlu aşağıdaki monad oluşur var. ReaderT, bir monad transformatördür ve State, State monad'tır ve AlgRO ve AlgState, sırasıyla, tek başına ve salt okunur durum için parametrize edilmiş veri türleridir. Böyle düzgün bir monad newtype ile transformatör, bir şey bundan yapmak istiyorsanız Şimdi,:

newtype SbT m i a = SbT { 
    runSbT:: m (SB i a) 
} 

nasıl bir yol izlemeliyiz? Bağlama yöntemini (Monad typeclass) bir araya getirmeyi bile başaramıyorum (MonadTrans'ın) daha az "kaldırma" ... Bence otomatik türetme yardımcı olabilir, ama bu durumda nasıl çalıştığını anlamak istiyorum.

Şimdiden teşekkürler.

cevap

10

SbT için tanımlamanın sizin istediğinizi sanmıyorum. Bu functor kompozisyonu'u tanımlar ve m parametresinin Functor veya Applicative olduğunu varsayarsak, bu özellikler korunmalıdır. Fakat böyle bir kompozisyon, genelde, diğer iki kişiden yeni bir monad oluşturmaz. Bu konuda daha fazla bilgi için this question'a bakın.

nasıl yapılır, istediğiniz monad trafosunu oluşturursunuz, o zaman? Monadlar doğrudan oluşturmazken, monofil transformatörleri oluşturulabilir. Yani mevcut olanlardan yeni bir transformatör oluşturmak için, aslında sadece bu kompozisyona bir isim vermek istersiniz. Bu, sahip olduğunuz newtype'dan farklıdır çünkü m'u doğrudan trafo yığına iletmek yerine uygularsınız. Mono transformatörlerini tanımlamak için akılda tutulması gereken bir şey, belirli bir şekilde "geriye doğru" çalışmalarıdır - bir monoya kompozit bir trafo uygularken, "en içteki" transformatör ilk çatlağı alır ve ürettiği dönüştürülmüş monad, bir sonraki transformatörün & c ile çalıştığı şeydir. Bunun, bir bağımsız değişkene bir işlev uygularken aldığınız sıradan farklı olmadığını unutmayın. (f . g . h) x, f bileşimde "ilk" işlev olsa bile, ilk olarak h argümanını verir.

Tamam, senin kompozit trafo uygulanacağına monad alıp uhm .... ayy, SB bir monad uygulanan zaten olduğu ortaya çıktı olduğu en içteki transformatör, onu geçmek gerekiyor. Hiç şaşkınlık bu işe yaramadı. İlk önce bunu kaldırmamız gerekecek. Nerede? State --we , numaralı telefonu kaldırabilir, ancak bunu yapmak istemiyoruz, çünkü sizin istediğiniz şeyin bir parçasıdır. Hmm, ama bekle - State tekrar nasıl tanımlanır? Oh evet: işte başlıyoruz. Aha, işte başlıyoruz. Oradan Identity çıkalım.

type SB' i m a = ReaderT (AlgRO i) (StateT (AlgState i) m) a 
type SB i a = SB' i Identity a 

Ama şimdi SB' bir monad transformatör gibi şüpheyle bakar:

type SB i a = ReaderT (AlgRO i) (StateT (AlgState i) Identity) a 

Sonra tembel serseri tekme: eşdeğer formda için

type SB i a = ReaderT (AlgRO i) (State (AlgState i)) a 

: Biz mevcut tanımından gitmek tanımı ve iyi bir sebeple, çünkü öyle. Bu yüzden newtype sarmalayıcı yeniden ve orada birkaç örneğini atmak: notu ait almaya

newtype SbT i m a = SbT { getSB :: ReaderT (AlgRO i) (StateT (AlgState i) m) a } 

instance (Functor m) => Functor (SbT i m) where 
    fmap f (SbT sb) = SbT (fmap f sb) 

instance (Monad m) => Monad (SbT i m) where 
    return x = SbT (return x) 
    SbT m >>= k = SbT (m >>= (getSB . k)) 

instance MonadTrans (SbT i) where 
    lift = SbT . lift . lift 

runSbT :: SbT i m a -> AlgRO i -> AlgState i -> m (a, AlgState t) 
runSbT (SbT m) e s = runStateT (runReaderT m e) s 

bir kaç şey: Burada runSbT işlevi yerine her biri için bir bestelediği "run" fonksiyonu alan erişimci değil, bildiğimiz yığındaki transformatör. Benzer şekilde, lift işlevinin, iki iç transformatör için bir kez kaldırması ve ardından son newtype sarıcısını eklemesi gerekir. Bunların her ikisi de, aslında bir kompozit olduğu gerçeğini saklayarak, tek bir monad transformatör olarak çalışır.

İsterseniz, oluşturulmuş transformatörlerin örneklerini kaldırarak, MonadReader ve MonadState için örneklerin yazılması da basit olmalıdır.

+0

bunu edeceğimizi. Teşekkürler! – dsign

2

Yeni türünüzde başka bir m eklemeye mi niyetlendiniz? Aşağıdaki öneririm: yazmak için instance Monad (Sb i) biraz kolaylaştırması gerekir

newtype Sb i a = Sb { runSb :: SB i a } 

.... Eğer gerçekten bir monad trafosu yazmaya çalışıyorsanız, o zaman trafoları sonuna kadar kullanmalısınız; örneğin,

type SBT m i a = ReaderT (AlgRO i) (StateT (AlgState i) m) a 
newtype SbT m i a = SbT { runSbT :: SBT m i a } 

ilgili ikinci nokta olarak, (her zaman "tam olarak uygulanan" olmalıdır çünkü) type eş anlamlılarını 'H-azaltmak için çoğu zaman tercih edilir; SB ve SBT ile bunu şu şekilde görünecektir:

type SB i = ReaderT (AlgRO i) (State (AlgState i)) 
type SBT m i = ReaderT (AlgRO i) (StateT (AlgState i) m) 
+0

Bu arada, 'SbT'den bu şekilde bir monad trafosu yapamazsınız. Transformatörler türden (* -> *) -> * -> * 'tür, yani bir monad ve argüman olarak bir tür alırlar. 'I' parametresinin ilk olması gerekir, bu yüzden kısmen uygulayabilirsiniz. –

İlgili konular