This works :
genAnimal :: Gen String
genAnimal = do
animals <- shuffle ["tiger","rabbit","dragon","snake","rat","ox","pig","sheep","horse","monkey","dog"]
return (head animals)
genWinner :: Gen String
genWinner = do
animal <- genAnimal
prize <- choose (10::Int,1000::Int)
return (unwords (replicate 3 animal) ++ " " ++ show prize)
genTicket :: Gen String
genTicket = do
animals <- replicateM 3 genAnimal
prize <- choose (10::Int,1000::Int)
return (unwords animals ++ " " ++ show prize)
genTickets :: Gen [String]
genTickets = do
tickets <- replicateM 6 (oneof [genWinner, genTicket])
return tickets
But it looks just ungainly, is there a more sensible way to combine these generators? It basically picks three random animals and then a random prize and then makes six tickets.
As @AJFarmar noted, you can use the elements
combinator to pick a random element from a list, instead of taking the head of a shuffled version:
genAnimal :: Gen String
genAnimal = elements ["tiger","rabbit","dragon","snake","rat","ox",
"pig","sheep","horse","monkey","dog"]
Also, an applicative style can generally be more succinct, particularly if you introduce helper functions for the pure computations that combine the results:
genPrize :: Gen Int
genPrize = choose (10,1000)
genTicket :: Gen String
genTicket = ticket <$> replicateM 3 genAnimal <*> genPrize
where ticket animals prize = unwords animals ++ " " ++ show prize
A few other miscellaneous improvements might come from:
unword
ed and glued together with blanks; String
form only when needed; gen
prefixes that clutter everything up vectorOf
alias for replicateM
which is a little more readable in this context. This might lead to something like:
{-# OPTIONS_GHC -Wall #-}
module Lottery where
import Test.QuickCheck
type Animal = String
data Ticket = Ticket [Animal] Int
pticket :: Ticket -> String
pticket (Ticket ts prz) = unwords ts ++ ' ':show prz
tickets :: Gen [Ticket]
tickets = vectorOf 6 (oneof [winner, loser])
where winner = Ticket <$> (replicate 3 <$> animal) <*> prize
loser = Ticket <$> (vectorOf 3 animal) <*> prize
animal = elements ["tiger","rabbit","dragon","snake","rat","ox",
"pig","sheep","horse","monkey","dog"]
prize = choose (10,1000)
main :: IO ()
main = print . map pticket =<< generate tickets
which I think looks pretty good.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.