Hi Isaac It sounds to me that your source of pseudo-randomness is an inherent part of your world state, as without it you're unable to calculate the next state.
You mention the problem of having to thread your PRNG through your functions, but I think the problem is broader than that. For instance, you may decide on a combat engine that takes in a source of randomness and two creatures as its arguments, only to decide at a later date that you also want the terrain to affect the battle. Usually we want to restrict what data a function cares about in order to make its effects more predictable, but because a game is modelling an analogue of the real world, any part of the current game state could potentially have an effect upon the outcome. I must admit I've yet to settle on an entirely satisfactory solution. You'd prefer to be able to restrain what a function cares about, but you also don't want to thread an argument through a dozen functions every time you want the function at the bottom to affect something new. The most straightforward solution is to thread the game state through your code as the first argument. It does solve the problem, but feels somewhat unsatisfactory. There might be a solution in lenses, zippers, or some similar structure. Instead of passing through the state bare, we pass through a view upon the state. How best to do this in Clojure is, I think, still an area of research. Alternatively you could think of it in terms of an event stream. You do as much as you can functionally, then return an event, or action, which results in a state change. This is similar to the "with gloves" approach that the IO monad uses. I apologise for not providing any concrete answers, but this has been something I've been thinking about as well. You can quite easily narrow the scope of data a function has access to, but it's very hard to widen it again. - James On 28 October 2014 19:08, Isaac Karth <isaacka...@gmail.com> wrote: > I've been working on some projects (roguelikes, story-generators) that > often have a reason to have a random outcome for things like procedurally > generating a map. Ideally, they would be deterministically psuduorandom, so > that I can generate the same results from the same seed. The part I'm > having trouble with is figuring out what method to use to implement this in > a functional way. > > The naive approach that first occurred to me was to pass a PRNG and seed > value into each function. That would certainly keep the functions > referentially transparent. But it would also require either rewriting a > bunch of functions that don't directly use the randomness themselves or > adding the RNG as part of the map that's already being passed. > > Plus, the seed should probably vary (deterministically) between calls to > the subfunctions. It's not too useful if all the rooms on a map have the > same type because they all pulled their die roll from the same-nth result > of the exact same seed. Maybe the seed could be created from the contents > of the vector or a UUID of a map object or something? > > The other suggestion I've run across is to rebind something like > clojure.data.generators/*rnd* for each high-level procedural generation > call. I think this requires the generation to be single threaded and > otherwise deterministic. At the moment I don't feel like I know enough > about how things work under the hood to say if this a good idea or not. > > I've poked around at the bigml.sampling and clojure.data.generators > libraries, which look useful for dealing with some of this, but I haven't > come across anything that directly addresses what kind of architecture to > use for deterministic randomness. This may be my inexperience. I feel like > I may be a bit too close to the problem, and I can't quite see what the > idiomatic answer is. Re-read SICP? Implement some kind of monad? Just bite > the bullet and pass the RNG+seed? Find the secret pure functional library > everyone is using for repeatable stochastic simulations? > > Does anyone have any advice on this? Or prior experience with approaches > that work? What are some best practices for approaching deterministic > simulations in an idiomatic, functional way? > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.