Paket Control.Monad.Writer
, veri yapıcısını dışa aktarmaz Writer
. Sanırım bu LYAH yazıldığında farklıydı.
Ghci'de MonadWriter tip sınıfını kullanma
Bunun yerine, writer
işlevi kullanarak yazarlar yaratırsınız . Örneğin, bir ghci oturumunda yapabilirim
ghci> import Control.Monad.Writer
ghci> let logNumber x = writer (x, ["Got number: " ++ show x])
Şimdi logNumber
yazarları yaratan bir işlevdir. Türünü sorabilirim:
ghci> :t logNumber
logNumber :: (Show a, MonadWriter [String] m) => a -> m a
Bu da bana, çıkarılan türün belirli bir yazıcıyı döndüren bir işlev olmadığını , daha çok MonadWriter
tür sınıfını uygulayan herhangi bir şey olduğunu söylüyor . Şimdi onu kullanabilirim:
ghci> let multWithLog = do { a <- logNumber 3; b <- logNumber 5; return (a*b) }
:: Writer [String] Int
(Giriş aslında tümü tek bir satıra girildi). Burada multWithLog
olmanın türünü belirledim Writer [String] Int
. Şimdi çalıştırabilirim:
ghci> runWriter multWithLog
(15, ["Got number: 3","Got number: 5"])
Ve tüm ara işlemleri kaydettiğimizi görüyorsunuz.
Kod neden böyle yazılıyor?
Neden MonadWriter
tür sınıfını oluşturmakla uğraşasınız ki ? Nedeni monad transformatörlerle yapmaktır. Doğru bir şekilde fark ettiğiniz gibi, uygulamanın en basit yolu Writer
bir çiftin üzerine yeni bir tür sarmalayıcıdır:
newtype Writer w a = Writer { runWriter :: (a,w) }
Bunun için bir monad örneği bildirebilir ve ardından işlevi yazabilirsiniz
tell :: Monoid w => w -> Writer w ()
basitçe girişini kaydeder. Şimdi, günlüğe kaydetme yeteneklerine sahip ama aynı zamanda başka bir şey yapan bir monad istediğinizi varsayalım - bir ortamdan da okuyabileceğini söyleyin. Bunu şu şekilde uygularsın
type RW r w a = ReaderT r (Writer w a)
Şimdi, yazıcı ReaderT
monad transformatörün içinde olduğu için , çıktıyı günlüğe kaydetmek istiyorsanız kullanamazsınız tell w
(çünkü bu yalnızca sarmalanmamış yazarlar ile çalışır), ancak işlevi aracılığıyla lift $ tell w
"kaldıran" , iç yazar monad. İki katmanlı transformatör istiyorsanız (ayrıca hata işleme eklemek istediğinizi söyleyin), o zaman kullanmanız gerekir . Bu hızla hantal hale gelir.tell
ReaderT
lift $ lift $ tell w
Bunun yerine, bir tür sınıfı tanımlayarak, bir yazarın etrafındaki herhangi bir monad dönüştürücü sarmalayıcısını bir yazarın kendisi haline getirebiliriz. Örneğin,
instance (Monoid w, MonadWriter w m) => MonadWriter w (ReaderT r m)
yani w
bir monoidse ve m
a ise MonadWriter w
, o ReaderT r m
zaman da a'dır MonadWriter w
. Bu, tell
işlevi doğrudan dönüştürülmüş monad üzerinde, onu monad transformatör aracılığıyla açıkça kaldırmak zorunda kalmadan kullanabileceğimiz anlamına gelir .