2010-09-22 34 views
5

Im khá mới với Haskell. Tôi có một kiểu dữ liệu:Haskell Random from Datatype

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

Tôi đã viết một Hiện dụ cho nó

Tuy nhiên, cho dù nó có ý nghĩa hay không, tôi muốn để có thể tạo ra một câu ngẫu nhiên. Làm thế nào tôi có thể thực hiện điều này trong Haskell?

Trả lời

5

Tạo số ngẫu nhiên là một ví dụ điển hình về hoạt động "không tinh khiết", vì gọi một trình tạo ngẫu nhiên hai lần sẽ mang lại kết quả khác nhau - bản chất của Haskell không cho phép điều này.

Vì vậy, bạn cần phải sử dụng một cái gọi là đơn lẻ Gen a đại diện cho một máy phát điện ngẫu nhiên , khi chạy, mang lại giá trị loại a.

May mắn thay, bạn có thể kết hợp các máy phát điện trong một cú pháp khá đẹp ...

Vì vậy, bạn chỉ cần một số library mà thực hiện một máy phát điện như vậy - và ở đây chúng tôi đi.

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

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

Cảm ơn phản hồi siêu nhanh, nhưng ý của bạn là gì bởi <$>? – SirLenz0rlot

+1

Ah, đó là từ 'Control.Applicative' - chỉ một số cú pháp đơn giản có nghĩa là bạn có thể áp dụng một hàm cho một giá trị ngẫu nhiên. – Dario

+5

Nó chỉ là 'fmap' – fuz

1

Cách dễ nhất là sử dụng mô-đun System.Random, trong gói ngẫu nhiên, vì vậy bạn có thể phải cài đặt trước.

mô-đun này định nghĩa để typeclasses:

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) 

Các typeclass, bạn phải thực hiện là ngẫu nhiên, cụ thể chức năng đầu tiên (tùy theo từng thứ hai chẳng có ý nghĩa, bạn chỉ có thể thực hiện như randomR = const randomrandom.? Bạn nhận được một máy phát ngẫu nhiên làm đầu vào, bạn phải tạo ra những gì bạn cần cho nó, và cung cấp cho trình tạo mới trở lại

Để tạo ra các giá trị ngẫu nhiên, bạn có thể sử dụng đơn vị State hoặc như sau:

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

Sau đó bạn có thể sử dụng hệ thống máy phát điện ngẫu nhiên bằng chức năng này:

randomIO :: Random r => IO r 

Nó được xác định trước và mang lại một giá trị khác nhau mỗi cuộc gọi.

Tuy nhiên, cuối cùng bạn phải tự quyết định cách xác định Ví dụ ngẫu nhiên của mình.

5

Phương thức yêu thích của tôi là sử dụng gói MonadRandom. Mặc dù nó sôi xuống đến cùng một điều như đi qua một số RandomGen xung quanh, nó hiện nó cho bạn và đảm bảo rằng bạn không mess up trong quá trình (chẳng hạn như đi qua một máy phát điện đã được sử dụng). Hơn nữa, Rand StdGen a có cách giải thích tốt đẹp về "phân bố xác suất a s".

Ví dụ của bạn, nó có thể trông như thế này:

-- 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 

Lưu ý sự kỳ diệu số 5 ở trên đó. Đó là vì vậy chúng tôi không nhận được 2 tỷ danh sách phần tử. Bạn có thể muốn điều chỉnh phân phối số lượng cụm từ trong danh sách được tạo ngẫu nhiên của mình.

Và để chạy nó, bạn có thể sử dụng evalRandIO hoặc nhiều thứ khác, nói như:

main = print =<< evalRandIO randSentence 
+1

Cảm ơn! Tôi thấy rằng thư viện Monad.Random không được bao gồm trong gói windows mới nhất. có lẽ vì một lý do? Kể từ khi tôi sao chép-dán các nguồn từ nó (http://www.haskell.org/haskellwiki/NewMonads/MonadRandom) vào một tập tin riêng, nó mang lại cho tôi những lỗi mà tôi không có ý tưởng làm thế nào để giải quyết nó: Khai báo cá thể bất hợp pháp cho 'MonadState s (RandT gm) ' – SirLenz0rlot

+1

Bạn cần cài đặt qua cabal, không sao chép và dán. Tôi cho rằng bạn đã cài đặt Nền tảng Haskell. Sau đó, khởi chạy "cabal install MonadRandom' tại dấu nhắc lệnh. Trước tiên, bạn có thể cần phải cập nhật cabal. – luqui

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

Run chọn trên danh sách bất kỳ.