2014-07-24 28 views
6

Haskell'deki rasgele hesaplamaları Control.Monad.Random kütüphanesi kullanarak bir zaman aşımıyla değerlendirmek istiyorum. gayet güzel şu işleri:Haskell - Rand monadındaki zaman aşımı hesaplamaları

ghci> import System.Timeout 
ghci> import Control.Monad.Random 
ghci> timeout 1000 . evalRandIO $ getRandomR (True, False) 
Just True 

Ancak, bu yaklaşım biz (alta yani değerlendirir) sonlandırır asla tip Rand StdGen a bir hesaplama varsa çalışmak görünmüyor. Örneğin:

İşte
ghci> let f = f :: Rand StdGen Bool 
ghci> timeout 1000 $ evalRandIO f 
Just 

GHCI baskılar "Sadece" ve ardından süresiz f değerlendirmek için çalışıyor asmak. Haskell çalışma zamanı hakkında daha fazla şey bilen biri, bunun neden olduğunu açıklamaktan ve etrafından nasıl geçeceğimi açıklayabilir mi? Tahminim, evalRandIO f ifadesinin WHNF'ye göre değerlendirilmiş olması ve timeout 10 hesaplamanın sonlanacağını düşünmesidir, ancak gerçekten hiçbir fikrim yok. Eğer

> Just x <- timeout 1000 $ evalRandIO f 
> :t x 
x :: Bool 
> x 
Interrupted. 

kendisi yani o WHNF ulaşıyor tamamlamakta hesaplama böyle bir şey yapmak olsaydı

cevap

5

Bu daha mantıklı olabilir, bu yüzden timeout yakalamak etmez. timeout 1000 işlevinin kendisi Just undefined'u tamamlar ve döndürür. Eğer bir alt değerlendirme yakalamak için timeout alabilirsiniz bir örnek daha sonra deepseqf değerlendiren bitirmek vermediğinde yüzden return f gerçekleştirebilirsiniz Nothing döndürür

> import Control.DeepSeq 
> :set +m -- Multiline mode 
> let f :: Bool 
|  f = f 
| 
> timeout 1000000 $ deepseq f (return f) 
Nothing 

Bunu bir saniye asılı olduğunu göreceksiniz olurdu.

Evet, sorunun nedeni, f = f'un NF yerine WHNF'ye değerlendirilmesinden kaynaklanmaktadır. NF'yi zorlamak için deepseq gibi bir şey kullanmanız gerekir.

> let f :: Rand StdGen Bool 
|  f = f 
| 
> timeout 1000000 $ evalRandIO $! f 
Nothing 
+0

teşekkür ederiz: Başka muhtemelen daha basit bir örnek sadece gibi $! operatörünü kullanmak olurdu! Seq/deepseq ve Haskell çalışma zamanı hakkında çok şey öğreneceğim. – user3873438

+0

@ user3873438 Adil olmak gerekirse, kendimi bulmak için bir GHCi oturumu yüklemem gerekiyordu. Tembellik bazı ilginç sorunlara neden olur, ancak çoğu zaman bunu düşünmek zorunda bile kalmazsınız. Çoğunlukla, belirli bir düzende, katılık konusunda endişelenmeye başlamanız gereken şeylere ihtiyaç duyduğunuz problemlere ulaştığınızda, bu durumda, 'zaman aşımı 1000' sonuna ulaşılmadan önce evalRandIO f'nin gerçekleşmesini istediniz. Böyle bir ilişkiyle, derinlikle açık olmak önemlidir, bu, “deepseq” ve “$!” Nin ne olduğudır. – bheklilr

+0

Ayrıca uzay sızıntıları ve paralellik için tembelliği endişelenmeniz gerekir. – PyRulez