繁体   English   中英

QuickCheck Haskell-生成随机彩票

[英]QuickCheck Haskell - generating random lottery tickets

这有效:

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

但是看起来很笨拙,是否有更明智的方式组合这些发电机? 它基本上会选择三只随机动物,然后随机抽取奖品,然后制作六张门票。

正如@AJFarmar指出的那样,您可以使用elements组合器从列表中选择一个随机元素,而不用改编版本的标题:

genAnimal :: Gen String
genAnimal = elements ["tiger","rabbit","dragon","snake","rat","ox",
                      "pig","sheep","horse","monkey","dog"]

此外,应用样式通常可以更简洁,特别是如果您为结合了结果的纯计算引入辅助函数时:

genPrize :: Gen Int
genPrize = choose (10,1000)

genTicket :: Gen String
genTicket = ticket <$> replicateM 3 genAnimal <*> genPrize
  where ticket animals prize = unwords animals ++ " " ++ show prize

其他一些其他改进可能来自:

  • 改变对生成器的看法,以生成最后要组合的单词,而不是必须解unword并用空格粘在一起的字符串;
  • 或者更好的方法是,引入一些数据类型以更好地为您的问题建模,并提供一个实用程序函数,仅在需要时才以适当的String形式打印它;
  • 摆脱使一切混乱的gen前缀
  • 使用vectorOf别名replicateM这是在这种情况下稍微更具有可读性。

这可能会导致类似:

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

我认为看起来不错。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM