Skip to content

Instantly share code, notes, and snippets.

@r00k
Last active April 2, 2024 20:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save r00k/71433db62959449762e26976261be9b7 to your computer and use it in GitHub Desktop.
Save r00k/71433db62959449762e26976261be9b7 to your computer and use it in GitHub Desktop.
-- I've successfully written a random generator for Circles.
randomCircle : Random.Generator Circle
randomCircle =
Random.map4
Circle
(Random.pair (Random.float -200 200) (Random.float -200 200))
(Random.float minimumRadiusLength maximumRadiusLength)
randomColor
(Random.float 0 maximumAlpha)
-- But now, I want a function that takes a Circle and either
-- returns that Circle or generates a random one.
sometimesRandomCircle : Circle -> Random.Generator Circle
sometimesRandomCircle circle =
-- This approach doesn't work. What might?
if Random.bool == True then
circle
else
randomCircle
-- I understand how to create a *fully* random Circle (or List of random Circles).
-- I want to return a random Circle half the time, and return the existing Circle the other half.
@anicholson
Copy link

@r00k Check out @xarvh's wonderful talk on Elm's generators: https://xarvh.github.io/talk-generators/#0

@r00k
Copy link
Author

r00k commented Oct 29, 2016

Thanks @anicholson. That helped clarify some things, but I'm still having trouble figuring out how to write sometimesRandomCircle.

@r00k
Copy link
Author

r00k commented Oct 29, 2016

Progress!

I now have this function type-checking:

sometimesRandomCircle : Circle -> Random.Generator Circle
sometimesRandomCircle circle =
      let
          circle' = Random.Extra.constant circle
      in
          Random.bool `Random.andThen` \b -> if b then circle' else randomCircle

Now, my goal is to use that to walk a List of Circles randomly replacing some with randomly-generated new Circles.

@r00k
Copy link
Author

r00k commented Oct 29, 2016

But how!?

@jmitchell
Copy link

I haven't played with generators yet, so I'm not sure I'll be much help. Can you use List.map on sometimesRandomCircle and a list of Circles to get a List (Random.Generator Circle)s? I'm looking at the docs and puzzle about how to turn that into a List Circle, but maybe you're not supposed to with generators?

@jmitchell
Copy link

There's no obvious way to go from List (Random.Generator a) -> Random.Generator (List a) either so...hmmm.

@xarvh
Copy link

xarvh commented Oct 29, 2016

sometimesReplace circle =
  Random.choices
    [ Random.Extra.constant circle
    , randomCircleGenerator
    ]

generateListWithRandomlyReplaceCircles listOfCircles =
   let
    listOfGenerators = List.map sometimesReplace listOfCircles
   in
    Random.Extra.together listOfGenerators

^_^

@r00k
Copy link
Author

r00k commented Oct 29, 2016

@xarvh - Thank you so much!

I'd been banging my head against this for a few hours, so it was so awesome to get unstuck.

@jmitchell
Copy link

This got me thinking a Hoogle for Elm would have helped. Happy to see there is one, and it even finds Random.Extra.flattenList when I query for List (Random.Generator a) -> Random.Generator (List a).

@r00k
Copy link
Author

r00k commented Oct 29, 2016

@jmitchell - Nice find! That would indeed have helped.

@mgold
Copy link

mgold commented Oct 29, 2016

Here's how I'd do it:

andThen = flip Random.andThen

swapSome : List Circle -> Random.Generator (List Circle)
swapSome circles =
  let
    doSwap oldCircle bool =
      if bool then
        Random.Extra.constant oldCircle
      else
        randomCircle
  in
    Random.list (List.length circles) Random.bool -- or use a non-uniform generator of booleans
    |> andThen (\bools -> List.map2 doSwap circles bools |> Random.Extra.flattenList)

Tricky little problem though!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment