1

I need to generate a string of names-date separated by spaces, where the name is just a random length of characters and the date is just four numbers. For example:

"dfghjkl-1234 derftgyhjuik-5678"

Currently I have this solution:

genArgs :: Gen String
genArgs = do
  cs <- listOf1 genCourse
  return (unwords cs)

genCourse :: Gen String
genCourse = do
  ns <- elements ["1111","1234","4567","1411","1284","4517"]
  ls <- listOf1 $ elements ['a'..'z']
  return (ls ++ "-" ++ ns)

But I had to hard-code the list of numbers because some of them have to repeat (have the same numbers) and if I just randomly picked them it would be very unlikely that somethin like this ever happens:

"dfghjkl-1234 derftgyhjuik-5678 gyhujik-1234"

What I would like, is to generate a random 4-digit number and then some of the elements of that string should have that repeat, say 25% of the time. I imagine this is achieved with frequency?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Cliff Stamp
  • 531
  • 5
  • 11
  • How about you still generate random elements but also make a new `Collection` type and make the generation of `Collection`s of values that has the correct distribution? – Thomas M. DuBuisson Aug 30 '18 at 02:18
  • 1
    [Panel 2](https://www.xkcd.com/568/) seems relevant here. I expect by the time you can say what you mean by "generate a random 4-digit number and then some of the elements of that string should have that repeat say 25% of the time" with enough precision for us to help you, you'll also be able to just write down the code that does it yourself. – Daniel Wagner Aug 30 '18 at 12:31

1 Answers1

3

Here's one attempt. You could start by defining a generator of those four-digit 'dates':

genDate :: Gen String
genDate = vectorOf 4 $ elements ['0'..'9']

Next, a function that, given a String will return a generator of 'courses':

genCourse :: String -> Gen String
genCourse ns = do
  ls <- listOf1 $ elements ['a'..'z']
  return (ls ++ "-" ++ ns)

In order to implement a genArgs function, one way to address the requirement could be to first generate a single date, and then use frequency to either return that randomly generated value, or other randomly generated dates:

genArgs :: Gen String
genArgs = do
  date <- genDate
  dates <- listOf1 $ frequency [(1, return date), (3, genDate)]
  courses <- traverse genCourse dates
  return $ unwords courses

One out of four values will be generated by the constant generator return date, and three out of four will be generated randomly by genDate.

This produces a list of 'date' strings that you can then traverse with genCourse.

Here's some sample values:

*Main Lib> sample genArgs
"u-8747"
"sd-2575 l-3069"
"rfn-1191 jbs-8962 kjtt-1909"
"ezbtrj-6167 t-3474 daaht-0834 puc-2266"
"epkbtz-8334 uj-8829 etu-9061 wkkro-5514 fque-4639 vgct-4572 daczohr-8683 zomo-5789"
"mkrnvyrjfu-6765 vunu-6869 xjd-1135 rkritwi-6869 odmvxec-4236 mirrfp-1715 jccla-0998 qyasxozuq-3713"
"cvyxjnvrqao-3675 rzsnkqplbv-3675 b-3675 ekchdgksbk-6463 nonz-3354 ue-3675 mwwoovthxusd-8882"
"vwffdntpwawo-4565"
"t-0278 dyauqxenubxjohr-7815 yvogox-5183 oz-4660 eufwzgabvo-3813 azetihbmuw-8622 tizuzbmacv-6102 tzqjz-9686 jsaaepngbi-7394 fzzpzykibohzf-7394 muhlolo-6770 tixpoi-7394 kqhvvw-5877 ulg-7394 ce-6817"
"y-3550 tfakitqwrhyrpu-6923 gwzpegkpxjn-7222 jkvuwsf-2819 il-2268 sfmxdh-0004 vqmalaisvtqtg-1759 acxn-3146 fuhwps-4534 rtqgqzndtjhiygan-3326 yktgeeww-2819 irtrpnh-0198 ghqs-2819 lofyzpejuzw-8408 hd-2647"
"kts-8877 kipbbttkzvopwkrmemsz-2158 xqblwsgdrhaupbfgg-0841 eminvqkvwl-9193 bjhzmafgnjyhdzuppar-9912 cg-7737 enjvjalpkstizymci-0039"

Notice that for example 6869 is repeated twice in the sixth value, and 3675 is repeated four times in the seventh sample.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736