2014-11-23 23 views
6

Sorunun there numaralı telefondan sorulmasını biliyorum ama düzgün bir yanıtın olduğuna inanamıyorum.Kısa devre VE IO Monad içinde

Ben bir (& &) içindeki yan etkiye gizlemek için iyi değil ama benim durumumda yan etki sadece outstide dünyada bir şey (bir dosyanın varlığını, vb değişiklik süresini kontrol kullanıcı a sormak kontrol ediyoruz anlıyorum evet/hayır quistion).

Peki, böyle bir şeye yol açma yolu nedir, bu nedenle cond1 öğesi yanlışsa, cond2 yürütülmez.

cond1, cond2 :: IO bool 


main = do 
    cond <- liftM2 (&&) con1 con2 
    if cond 
    then result1 
    else result2 

Ben cond <- all [con1, con2] veya eşdeğeri gibi bir şey bekliyordum, ama bir şey bulamıyorum.

Güncelleme

Ben manuel çözümün bir sürü görebilirsiniz. Hala bu işlevin bir yerde bulunmadığına şaşıyorum. Tembelliğin değerlendirilmesinin bir avantajı sadece && kodunda kısa kodlama yapmak değil, zorunlu modundayken Haskell, && kısa devre bile yapamaz. Her ne kadar tüm çözüm bir şekilde ve değerlendirmeyi kısa devre yaptırmak için kullanıyor olsa da. Genel bir tembel liftM2 yapmanın bir yolu yok mu?

+0

tanımlanmıştır, bu fark: xs: 've M, [] = TRUE ve daha sonra' ve M, (x geri) = do b <- x; b ve o zaman eğer xMs yanlış döndüyse false ' – ErikR

+0

Aşağıda söylediğim gibi 'veM' monad-döngüler kitaplığında tanımlanır. Burada http://hackage.haskell.org/package/monad-loops gibi şeyler bulmayı bekler. -0.4.2.1/docs/Control-Monad-Loops.html # v: andM – Michael

+0

@Arthur güncellemeyi görmedi. – mb14

cevap

3

İstediğiniz işlemin açıkça tanımlanması basittir.

x `shortCircuitAnd` y == shortCircuitAnd x y 
+1

'r1 & r2' aslında r2'dir, çünkü' r'' tarafından 'if' tarafından garanti edilir. Bu nedenle, r1 <- x; Eğer r1 ise geri dönerse False işe yarıyor. – chi

8

Bu Pipes.Prelude.and effectfully oluşturulan Koşullamalar ve eğer kısa devre tembel bir dere üzerinden geçerken yaptığı iştir: Elbette

shortCircuitAnd :: Monad m => m Bool -> m Bool -> m Bool 
shortCircuitAnd x y = do 
    r1 <- x -- perform effect of x 
    if r1 
    then y -- perform effect of y and return result 
    else return False -- do *not* evaluate or perform effect of y 

, sen komutu ters tırnak kullanarak, hem bu fonksiyon infix kullanabilirsiniz bunlardan herhangi False şunlardır:

import Pipes (each) 
import qualified Pipes.Prelude as Pipes 

conds :: [IO Bool] 
conds = ... 

main = do 
    cond <- Pipes.and (each conds >-> Pipes.sequence) 
    print cond 

İlgili linkler:

3

Biz MonadPlus bir örneği olan MaybeT gibi bir tek hücreli transformatörü kullanabilir. Buradaki fikir, False sonuçlarını mzero s'ye çevirmek için guard kullanmaktır. Ve sonra ortaya çıkan Maybe'u Bool'a dönüştürürüz.

import Control.Monad.Trans 
import Control.Monad.Trans.Maybe 

effyand :: (Functor m, Monad m) => [m Bool] -> m Bool 
effyand = fmap isJust . runMaybeT . mapM_ (lift >=> guard) 
+1

Sanırım bir kod bloğu bırakmak yerine cevabınıza biraz açıklama eklemek daha iyidir. – AdamMc331

3

Ben

newtype AllM m = AllM { getAllM :: m Bool } 

instance (Monad m) => Monoid (AllM m) where 
    mempty = AllM (return True) 
    mappend (AllM u) (AllM v) = AllM $ 
     u >>= \x -> if x then v else return False 

ve sonra getAllM . mconcat . map AllM $ [con1, con2] gibi bir Monoid tanımlamak istiyorum.

> let test1 = putStrLn "This test succeeds" >> return True 
> let test2 = putStrLn "This test fails" >> return False 
> andM [test1,test2,undefined,undefined] 
This test succeeds 
This test fails 
False 

: diyeceğiz, olsun sonra

andM = foldr (&&&) (return True) 
    where ma &&& mb = ma >>= \p -> if p then mb else return p 

: En basit sadece and tanımını taklit

İlgili konular