2010-09-22 18 views
5

Haskell'e oldukça yeni geldim. Ben bir veri türü vardır:Haskell Datatype'dan rastgele

data Sentence= Prop Int 
      | No Sentence 
      | And [Sentence] 
      | Or [Sentence] 
      deriving Eq 

ben zaten

Ancak mantıklı olsun ya da olmasın, ben rastgele Cezasını oluşturabilmek için istiyorum için göster örneğini yazdım. Haskell'de bunu nasıl yapabilirim?

cevap

5

Rasgele sayı üretimi, "saf olmayan" bir işlemin tipik bir örneğidir, çünkü rastgele bir üreteci iki kez çağırmak elbette farklı sonuçlar verir - Haskell'in doğası buna izin vermez.

Bu nedenle, çalıştırıldığında, tip a bir değer elde edilir, yani bir rastgele jeneratörü temsil eden bir sözde monad Gen a kullanmak gerekir. Gidip burada -

Neyse ki,

Yani, sadece bazı tür bir jeneratör uygulayan library gerek ... oldukça güzel sözdiziminde bu jeneratörler birleştirebilirsiniz.

randomNo = No <$> randomSentence 
randomProp = Prop <$> choose (1, 10) 
[...] 

randomSentence = oneOf [randomNo, randomProp, ...] 
+0

Mükemmel yanıt için teşekkürler, ancak <$> ile ne demek istiyorsunuz? – SirLenz0rlot

+1

Ah, 'Control.Applicative' den - sadece bazı basitleştirilmiş sözdizimi, bir işlevi rastgele bir değere uygulayabileceğiniz anlamına gelir. – Dario

+5

Sadece 'fmap' – fuz

1

kolay yolu rastgele pakette var, modül System.Random kullanmaktır, bu nedenle muhtemelen ilk yüklemeniz gerekir.

Bu modül typeclasses tanımlar.

class RandomGen g where 
    next :: g -> (Int,g) 
    -- ... 

class Random r where 
    random :: RandomGen g => g -> (a,g) 
    randomR :: RandomGen g => (r,r) -> g -> (a, g) 

typeclass, sen uygulamak zorunda özgü, Random birinci fonksiyonu (ikinci hiçbir mantıklı olarak, sadece randomR = const random gibi uygulayabilirsiniz Ne random yapar mı? girdi olarak, size bunun için gerekenleri oluşturmak ve geri yeni jeneratör vermek zorunda rastgele jeneratör almak

sizin rastgele değerler üretmek için, böyle State monad, ya da bir şey kullanabilirsiniz ya:.

random g = (myResult,gn) where 
    (random1,g1) = next g 
    (random2,g2) = next g2 
    -- ... 

Daha sonra bu işlev tarafından sistemlerini rastgele jeneratör kullanabilirsiniz:

randomIO :: Random r => IO r 

Bu önceden belirlenir ve her çağrı farklı bir değeri verir. Ancak son olarak, Rastgele örneğinizi nasıl tanımlayacağınıza kendiniz karar vermelisiniz.

5

Favori yöntemim MonadRandom paketini kullanmaktır. Her ne kadar yaklaşık RandomGen'u geçerek aynı şeyle aynı kaynağa gelse de, sizin için yapar ve süreçte dağılmamanızı sağlar (zaten kullanılan bir jeneratörü geçmek gibi). Ayrıca, Rand StdGen a "a s olasılık dağılımı" nın güzel yorumuna sahiptir. senin Örneğin

, bu gibi görünebilir: sihirli sayı 5 oraya

-- a type for probability distributions 
type Dist = Rand StdGen 

-- pick uniformly between a list of values 
uniform :: [a] -> Dist a 
uniform xs = do 
    ix <- getRandomR (0, length xs - 1) 
    return (xs !! ix) 

-- return a list of elements generated by the given distribution 
randList :: Int -> Dist a -> Dist [a] 
randList maxElems dist = do 
    elems <- getRandomR (0, maxElems) 
    sequence (replicate elems dist) 

-- return a probability distribution of sentences 
randSentence :: Dist Sentence 
randSentence = do 
    -- choose one of these four distributions by a uniform distribution 
    -- (uniform [...] returns a distribution of distributions) 
    dist <- uniform [ 
     Prop <$> getRandom, 
     No <$> randSentence, 
     And <$> randList 5 randSentence, 
     Or <$> randList 5 randSentence ] 
    -- and sample the one we chose 
    dist 

Not. Bu yüzden 2 milyar eleman listesi almıyoruz. Rastgele oluşturulmuş listelerinizdeki terimlerin sayısını dağıtmak isteyebilirsiniz.

main = print =<< evalRandIO randSentence 
+1

Teşekkürler! Monad.Random kitaplığının en son Windows paketine dahil olmadığını buldum. belki bir sebepten dolayı? Kaynağı (ondan http://www.haskell.org/haskellwiki/NewMonads/MonadRandom) kendi dosyasına kopyalayıp yapıştırdığımdan beri, hataların nasıl çözüleceğine dair bir fikrim yok: Hatalı örnek beyanı MonadState s (RandT gm) ' – SirLenz0rlot

+1

için Cabal ile kopyalamanız ve yapıştırmanız gerekmemektedir. Haskell Platform'un kurulu olduğunu kabul ediyorum. Daha sonra komut isteminde 'cabal monadRandom'u yükleyin. İlk önce "cabal update" 'e ihtiyacınız olabilir. – luqui

1
pick :: [a] -> IO a 
pick xs = randomRIO (0, length xs - 1) >>= return . (xs !!) 

çalıştırın herhangi bir liste üzerinde almak:

Ve evalRandIO veya birçok başka şeyler kullanabilirsiniz çalıştırmak için, gibi söylerler.