2015-06-12 23 views
11

Öncelikle tanımlayıcı olmayan başlık için özür dilerim. Aslında neler olup bittiğine dair hiçbir fikrim olmadığı için, onu daha spesifik yapamam.GHCI neden bir hatadan sonra "sıkışmış" durumda hata yapıyor?

Sorularım için şimdi.

*Main> rndSelectIO' "asdf" 2 >>= putStrLn 
af 
: Ben ghci bu yüklediğinizde bu geçerli argümanlar için düzgün çalışır Şimdi

rndSelect' :: RandomGen g => [a] -> Int -> g -> ([a], g) 
rndSelect' _ 0 gen = ([], gen) 
rndSelect' [] _ _ = error "Number of items requested is larger than list" 
rndSelect' xs n gen = ((xs !! i) : rest, gen'') 
        where (i, gen') = randomR (0, length xs - 1) gen 
          (rest, gen'') = (rndSelect' (removeAt xs i) (n - 1) gen') 

rndSelectIO' :: [a] -> Int -> IO [a] 
rndSelectIO' xs n = getStdRandom $ rndSelect' xs n 

removeAt :: [a] -> Int -> [a] 
removeAt xs n 
    | length xs <= n || n < 0 = error "Index out of bounds" 
    | otherwise = let (ys, zs) = splitAt n xs 
        in ys ++ (tail zs) 

: Ben rastgele bir listeden n öğeler seçmelisiniz 99 Haskell problems, sorunu 23 için şu pasajı uygulamış

*Main> rndSelectIO' "asdf" 5 >>= putStrLn 
dfas*** Exception: Number of items requested is larger than list 
*Main> rndSelectIO' "asdf" 2 >>= putStrLn 
*** Exception: Number of items requested is larger than list 

Gördüğünüz gibi,: Ben sınırların dışında bir dizin kullandığınızda

Ancak, garip şeyler 2 (benim için) beklenmeyen şeyler gerçekleşir:

  1. Doğrudan bir hata vermek yerine, önce girişin bir permütasyonunu yazdırın.
  2. Bir kez bir hata verdikten sonra artık çalışmayacaktır.

1. Bunun tembel değerlendirme ile ilgisi olduğundan şüpheleniyorum, ancak neden 2'nin gerçekleştiğine dair hiçbir fikrim yok. Burada neler oluyor?

+0

Etkileşimli oturumdaki her satır, hiçbir zaman bitmeyen aynı örtük "do" ifadesinin içinde yer alır, böylece her satır bir sonraki sonuca geçer. – chepner

cevap

13

getStdRandom işlevi temel olarak bir global değişkende StdGen değerini arar, üzerinde bazı işlevler çalıştırır, yeni ekimi genel değişkene geri döndürür ve sonucu arayan kişiye döndürür.

Söz konusu işlev bir hata ile dönerse, bu hata genel değişkene aktarılır. Şimdi bu küresel değişkeni kullanma girişimleri bir istisna atar. (Ben global değişkenler kötüdür söyledi! ;-))

elle kendiniz getStdGen aramayı deneyin. Geçerli rastgele tohumu basacak veya bir istisna atar. Bir istisna atarsa ​​... senin problemin var.

Sesi sıfırlamak için setStdGen kullanabilirsiniz.

+0

Yani bir tembellik sorunu değil mi? 'getStdRandom'' StdGen'de bir hata koymamalıdır. – mariop

+0

@mariop Bunun için tek bir global değişkene izin verilmesi, ilk etapta bir kırılmadır (ör., Iplik güvenliği tehdit edilebilir). Ama evet, sanırım küresel değişkenin içine bir istisnayı yeniden yerleştirmekten kaçınmak için biraz çirkin bir şey yapmalıyız ... – MathematicalOrchid

+0

Bu nasıl gerçek dünya uygulamalarında ele alınmaktadır? Herkes kendi rasgele jeneratörü her zaman başlatır mı? Ve bu kasıtlı bir tasarım kararı mıdır, yoksa getStdRandom'daki hataları yakalamamak bir gözetim miydi? – Tiddo

İlgili konular