2015-09-26 26 views
10

Çoğu zaman ben Haskell (C gibi continue) yineleme kalanını atlama ihtiyacı kendimi buldum:`Monad` döngüsünde nasıl devam edebilirim?

forM_ [1..100] $ \ i -> 
    a <- doSomeIO 
    when (not $ isValid1 a) <skip_rest_of_the_iteration> 
    b <- doSomeOtherIO a 
    when (not $ isValid2 b) <skip_rest_of_the_iteration> 
    ... 

Ancak, ben bunu yapmak için kolay bir yol bulamadılar. Bildiğim tek yol muhtemelen Trans.Maybe, ama çok önemsiz bir şey elde etmek için bir monad dönüşümü kullanmak gerekli mi?

+2

: Ørjan Johansen yararlı tavsiyeler @ kullanma

, burada bir basit örneğidir. Gördüğüm en ilginç olanı muhtemelen https://hackage.haskell.org/package/loops – dfeuer

+3

Monad transformatörlerinin asla gerekli olmaması - sadece uygun. –

cevap

13

Haskell'de böyle döngüler büyü olmadıklarını unutmayın ... bunlar sadece kendinize yazabileceğiniz birinci sınıf şeylerdir.

Değeri için, MaybeT'u Monad transformatörü olarak düşünmenin çok faydalı olduğunu düşünmüyorum. Bana göre MaybeT sadece mappend ve mempty alternatif uygulamalarını vermek Product, Sum, First, And vb nasıl kullandıklarını gibi (>>=) alternatif uygulaması vermek için sadece bir newtype sarıcı ... olduğunu.

Şu an için (>>=) sizin için IO a -> (a -> IO b) -> IO b. Ancak (>>=)'un IO (Maybe a) -> (a -> IO (Maybe b) -> IO (Maybe b) olması daha kullanışlı olacaktır. Bir Nothing döndüren ilk eyleme ulaşır ulaşmaz, daha fazla "bağlamak" gerçekten imkansız. Bu tam olarak MaybeT'un size verdiği şeydir. Ayrıca, guard :: IO a yerine guard, guard :: Bool -> IO (Maybe a) "özel örneği" alabilirsiniz.

forM_ [1..100] $ \i -> runMaybeT $ do 
    a <- lift doSomeIO 
    guard (isValid1 a) 
    b <- lift $ doSomeOtherIO a 
    guard (isValid2 b) 
    ... 

ve bu kadar

MaybeT :) Ya sihirli değildir ve iç içe geçmiş when s kullanarak temelde aynı etkiyi elde edebilirsiniz. Bu değil gerekli, sadece çok basit ve işler yapar bulunuyor temizleyici :)

+0

Harika cevap için teşekkürler. Ancak, belki de açıklığa kavuştum (sorumu düzenliyorum), ama istediğim şey bir "ara" değil, "devam et". İnce bir fark var --- tüm döngü değil, * yinelemenin * geri kalanını atlamak istiyorum. Soruyu değiştirdim. – trVoldemort

2

sen eylemleri gerçekleştirmek ve/veya özet değerini üretmek için bir liste veya başka bir kap üzerinde döngü istiyorum ve her zamanki buluyoruz varsa for_ ve foldM gibi kullanışlı araçlar, iş için yeterince iyi değil, iş için yeterince güçlü olan foldr'u düşünmek isteyebilirsiniz. Bir kapsayıcı üzerinde gerçekten döngü yapmadığınızda, düz eski özyinelemeyi kullanabilir veya https://hackage.haskell.org/package/loops veya (çok farklı bir tat için) https://hackage.haskell.org/package/machines veya belki de https://hackage.haskell.org/package/pipes gibi bir şeyi kullanabilirsiniz.

loop [] = return() -- done with the loop 
loop (x:xs) = 
    do a <- doSomeIO 
    if ...a... 
     then return() -- exit the loop 
     else do -- continuing with the loop 
       b <- doSomeMoreIO 
       if ...b... 
        then return() -- exit the loop 
        else do -- continuing with the loop 
          ... 
          loop xs -- perform the next iteration 

ve sonra onu çağırmak: Burada

+0

Teşekkürler. Döngüleri deniyorum ama işe yaramadım. Bu soruya bir göz atabilir misiniz (http://stackoverflow.com/questions/32918416/how-do-i-use-break-in-the-package-loops)? – trVoldemort

5

çıplak kemikleri özyineleme kullanarak yapacağını nasıl

loop [1..100] 

Sen Control when fonksiyonu ile biraz bu çeki düzen olabilir. Monad:

loop [] = return() 
    loop (x:xs) = 
     do a <- doSomeIO 
     when (not ...a...) $ do 
      b <- doSomeMoreIO 
      when (not ...b...) $ do 
      ... 
      loop xs 

da Control.Mona içinde unless yoktur Kullanmayı tercih edebileceğiniz d.Hackage çeşitli türlerdeki döngüler sunan birkaç paketleri vardır

import Control.Monad 

loop [] = return() 
loop (x:xs) = do 
    putStrLn $ "x = " ++ show x 
    a <- getLine 
    when (a /= "stop") $ do 
    b <- getLine 
    when (b /= "stop") $ do 
    print $ "iteration: " ++ show x ++ ": a = " ++ a ++ " b = " ++ b 
    loop xs 

main = loop [1..3] 
İlgili konular