map :: (a -> b) -> [a] -> [b]
putStrLn :: Show a => a -> IO()
map putStrLn :: Show a => [a] -> [IO()]
IO()
eylemlerinizin bir listesi var.
main :: IO()
Tek IO()
eyleme onlara katılmak gerekir. Yapmak istediğiniz ne
sequence/sequence_ bu IO()
işlemlerin her birini gerçekleştirmek için geçerli:
kolaylık sağlamak için
sequence :: Monad m => [m a] -> m [a]
sequence_ :: Monad m => [m a] -> m()
, mapM/mapM_ listesi ve sekans çıkan monadic sonuçları üzerinde bir işlev eşler.
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_ :: Monad m => (a -> m b) -> [a] -> m()
Yani sabit kod şu şekilde görünecektir:
main = mapM_ putStrLn $ map fizzBuzz [1..100]
Muhtemelen bu gibi yazmak isterim rağmen:
main = mapM_ (putStrLn . fizzBuzz) [1..100]
Hatta bu:
main = putStr $ unlines $ map fizzBuzz [1..100]
Kendi sequence
ürünümüzü yazalım. Ne yapmasını istiyoruz?
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return $ x:xs
- listede sol şey yoksa, iade (monadın içine enjekte) sonuçlarının boş listesi.
- Aksi takdirde, monadın içinde
- bağlama ilk sonucu (
IO
monadın için, bu yürütme anlamına gelir). Listenin geri kalanı için
sequence
; sonuç listesini ekle.
- İlk sonuca ve diğer sonuçların listesine bir kez geri dönün.
ghc kütüphanesi daha foldr (liftM2 (:)) (return [])
gibi bir şey kullanır ama bu yeni gelen açıklamak zordur; Şimdilik, sadece benim sözüm ona eşdeğer olsun.Sonuçların kaydını tutmakla uğraşmadığı için,
sequence_
daha kolaydır. GHC'nin kütüphanesi, sequence_ ms = foldr (>>) (return()) ms
olarak uygular. "Sonucunu atmak a
yoktur; b
yapmak; hellip & sonucu atmak; nihayet, ()
dönüş"
başka deyişle
sequence [a, b, c, d]
= foldr (>>) (return()) [a, b, c, d]
= a >> (b >> (c >> (d >> return())))
: Sadece foldr
tanımını genişletmek edelim. Öte yandan
mapM f xs = sequence $ map f xs
mapM_ f xs = sequence_ $ map f xs
, hatta alternatif
unlines
çözeltisi ile hiç monads bilmek gerekmez.
unlines
ne yapar? Eh, lines "a\nb\nc\nd\n" = ["a", "b", "c", "d"]
, tabiki unlines ["a", "b", "c", "d"] = "a\nb\nc\nd\n"
.
=
unlines ["1", "2", "Fizz", ..]
=
"1\n2\nFizz\n..."
= ve
putStr
'a gider. Haskell'in tembellik büyüsü sayesinde, tam dizinin bellekte yapılması gerekmiyor, bu yüzden bu mutlu bir şekilde
[1..1000000]
ya da daha yükseğine gidecek :)
Teşekkür ederim, haskell'in böyle bir şey olduğunu biliyordum ama anlayamadım dışarı! şimdi anladım * neden * işe yarıyor ... :) – RCIX
Açıklamaya çalıştığım gibi, “IO()” eylemlerinin bir listesini oluşturdunuz, ama * ne * ile ne yapmak istediğinizi söylemelisiniz. 'sequence', burada istediğiniz gibi olan sırayla monadların bir listesini çalıştırır. Son çözümüm onun yerine, fizik/vızıltı dizelerini “IO” nun garip ülkesine girmeden önce tek bir çok satırlı dizeye katıyor. – ephemient
Evet, sadece bir monad ve IO eylemi arasındaki bağlantıyı yapmadım - bu öğreticiden bazıları hala biraz bulanık – RCIX