Monad fonksiyonları için Transformers vs Geçen parametreleri
Haskell ama Monad Transformers nasıl kullanılabileceğini anlamak için yeni duyuyorum. Ama ben yine de zorluklar işlev çağrıları için parametreleri üzerinden geçen iddia avantajı kapma.
Wiki dayalı Monad Transformers Explained, temelde kusurlu bir Nesne olarak tanımlamış
data Config = Config Foo Bar Baz
ve onu geçmek, bu imza ile işlevleri yazmak yerine
client_func :: Config -> IO ()
ReaderT bir Monad Transformer kullanıyoruz ve imza değiştirin
client_func :: ReaderT Config IO ()
Config çekerek sonra 12 ** sadece bir çağrı.
İşlevi runReaderT client_func c
13 *değişiklikleri arayın
Güzel.
Ama neden bu benim uygulama daha basit yapar mı ?
1 - Monad Transformers birlikte bir başvuru formu için modüller/fonksiyonlar bir sürü dikiş atarken bir ilgi var sanırım. Ama bu anlama benim durur. Biri bizi aydınlatabilir misiniz?
2 - bir büyük yazmak nasıl herhangi bir belge bulamadımmodülernerede Haskell modüllerinde uygulama ve uygulamaları API gizlemek gibi (kısmen) diğer modüllerden kendi Devletleri ve çevrelerinden gizlemek çeşit göstermek. Herhangi bir işaretçiler lütfen ?
(Edit: Real World Haskell Birleşik Devletleri ".. bu yaklaşım bir Monad Transformers] ... daha büyük programları destekliyor." ama net bir örneği olduğunu iddia) gösteren yok
Aşağıdaki Chris Taylor Altına Cevap yazınız
Chris mükemmel Config, Devlet,vb şifrelenmiş açıklıyor... Trafo bir Monad içinde iki fayda sağlar:
- Önler daha yüksek seviyede işlev olması için bakımını kendi türüne imza tüm gerekli parametreleri tarafından (alt)işlevleri çağırır ama gerekmediği için kendi kullan (
getUserInput
fonksiyon) - ve sonuç olarak yapar yüksek seviye fonksiyonlar daha esnek bir değişimin içeriği Trafo Monad (diyelim ki eklemek istediğiniz bir
Writer
bunu sağlamak için giriş düşük seviyeli fonksiyon)
Bu yüzden tüm fonksiyonları imza değiştirme pahasına birlikte kaçıyorlar "" Trafo Monad.
Yani 1 soru tamamen kaplıdır. Chris teşekkür ederim.
Soru 2 this SO post cevaplanır
CEVAP
Hadi şu biçimde bazı yapılandırma bilgilerini gereken bir program yazıyoruz ki:
data Config = C { logFile :: FileName }
Program yazmak için bir yolu açıkça yapılandırma etrafında işlevleri arasında geçiş için. O-cekti var olmak güzel eğer biz sadece geçmek için fonksiyonları kullanımı açıkça, ama ne yazık ki emin değiliz, bir işlevi olabilir aramalısınız, başka bir işlevi kullanan yapılandırma, yani zorla geçmek gibi bir parametre her yerde (aslında, bu eğilimi olması düşük seviye işlevleri kullanmaya ihtiyaç yapılandırma, hangi güçler bize geçmek için tüm üst düzey fonksiyonları gibi).
Böyle program yazalım, sonra yeniden yazmak Reader
monad kullanarak ve bakalım ne olacak.
Seçenek 1. Açık yapılandırma geçiyor
Bunun gibi bir şey ile bitireceğiz:
readLog :: Config -> IO String
readLog (C logFile) = readFile logFile
writeLog :: Config -> String -> IO ()
writeLog (C logFile) message = do x <- readFile logFile
writeFile logFile $ x message
getUserInput :: Config -> IO String
getUserInput config = do input <- getLine
writeLog config $ "Input: " input
return input
runProgram :: Config -> IO ()
runProgram config = do input <- getUserInput config
putStrLn $ "You wrote: " input
Yüksek düzey pointer fonksiyonları her zaman etrafında config dikkat edin.
Seçenek 2. Okuyucu monad
Alternatif Reader
monad kullanarak yeniden yazmak için. Bu düşük seviyeli fonksiyonları biraz karıştırıyor:
type Program = ReaderT Config IO
readLog :: Program String
readLog = do C logFile <- ask
readFile logFile
writeLog :: String -> Program ()
writeLog message = do C logFile <- ask
x <- readFile logFile
writeFile logFile $ x message
Ama bizim ödül olarak, yüksek seviyeli işlevler biz asla yapılandırma dosyasına başvurmak gerekir, çünkü daha kolaydır.
getUserInput :: Program String
getUserInput = do input <- getLine
writeLog $ "Input: " input
return input
runProgram :: Program ()
runProgram = do input <- getUserInput
putStrLn $ "You wrote: " input
Daha da alma
Yeniden yazmak getUserİnput ve runProgram tür imzalar olmamız olabilir
getUserInput :: (MonadReader Config m, MonadIO m) => m String
runProgram :: (MonadReader Config m, MonadIO m) => m ()
bize eğer herhangi bir nedenle Program
temel türünü değiştirmek istediğimize karar verirsek daha sonra, esneklik çok verir. Eğer programımız için değiştirilebilir devlet eklemek istiyorsak örneğin, yeniden yapabiliriz
data ProgramState = PS Int Int Int
type Program a = StateT ProgramState (ReaderT Config IO) a
getUserInput
runProgram
değiştirmek zorunda değiliz. - iyi çalışmaya devam edecekler.
N. B. ben yazın Bu yazıya bakmadım, bırak kaçmayı denedi. Hatalar olabilir!
Nasıl her yerde parametreleri play2 ge...
** (Çift yıldız) ve * (yıldız) Python ...
Nasıl bir toplu iş dosyası komut satır...
Düz Monad İngilizce? (FP arka plan içi...
PHP fonksiyonları için Büyük-O listesi...