POV-Ray : Newsgroups : povray.off-topic : More random humous : Re: More random humous Server Time
10 Oct 2024 03:18:40 EDT (-0400)
  Re: More random humous  
From: Darren New
Date: 8 Oct 2008 06:19:59
Message: <48ec894f$1@news.povray.org>
Warp wrote:
>   So basically if two completely different functions in completely separate
> parts of the program, both being called through long separate chains of
> function calls would require using the same RNG stream, you would have to
> put the seed parameter to each single function in both chains, even though
> most of the functions don't use the RNG for anything themselves.

In a purely functional language, yes. If the result of the function 
depends on only its arguments, then quite reasonably if the function's 
result depends on the result of the RNG stream, you have to pass the RNG 
stream into the function, even if it's only used at lower levels.

Yes, it's rather a PITA. It's how Erlang works, too, except there's a 
back door where you can stuff some of your values into a per-process 
hash table (where a "process" is a very small and efficient thing in 
Erlang). You have to take care not to walk on someone else's key, tho.

>   If you add calling the RNG to some function in the future, and you want
> it to use the same RNG stream, you will then have to add the seed as a
> parameter to the function and modify all the lines where that function is
> called (which possibly requires to add the seed as parameter to those
> functions where those lines are, etc.) 

Yes. And it shows you that calling that new function may now alter the 
results from other functions that used to take the same stream.

 > If you later remove the need for the
> RNG, then the parameter becomes obsolete, but are you going to remove it?

Recall that all looping is done with recursion, too, so you wind up 
calling yourself a lot more than in other languages, too. So you wind up 
not only having to add it to all the callers, but to all the "loops" as 
well.

>   How do you even create objects which have a state in Haskell? Suppose
> that you want to create, for example, sprite objects, each one with their
> own state. This state could be, for example, an image (which may be shared
> among several sprite objects, or different from other sprite objects, and
> which might even change in the future due to some event), their location
> on screen and a RNG stream specific to that sprite object. When you call
> some update function of the sprite, then the sprite could eg. call the RNG
> function using its own RNG stream, and update its own position on screen
> based on that. Given that you can't (in theory) assign anything to anything
> else, how can you make an object which changes its own state?

You might have a structure called "World" that you pass to a function 
Update.

Function Update(World) ->
    ThisJoysticks = Read_Joysticks()
    NewPlayers = Update_Players(ThisJoysticks, World.Players)
    NewSprites = Update_Sprites(World.Sprites)
    NewWorld = World{NewPlayers, NewSprites}
    Update(NewWorld)

Function Update_Sprites(Sprite_List) ->
    NewSprits = map UpdateOneSprite Sprite_List
function UpdateOneSprite(Sprite) ->
    ThisRNG = Sprite.RNG
    ThisPos = Sprite.Position
    NewRNG = Rand(ThisRNG)
    NewPos = ThisPos + NewRNG.value
    NewSprite = Sprite{Sprite.Image, NewRNG, NewPos}
    Draw(NewSprite.Image, NewSprite.Position)
    return NewSprite

Basically, you track the world, and create a new world from scratch
each time thru the loop by recalculating what all the new parts are
based on the old parts. And you pass up and down everything you need.
It's fairly ugly.

I saw a blog about it that gave a really good explanation, but I can't 
seem to find it any more. I'll keep looking.

> This feels like the ideal design for things like for example sprites, as
> described above.

Not unreasonable. For things like games, where you have a bunch of 
independent actors, an OO approach works well and intuitively.

There's another way to do it, tho, which is to have independent 
functions of time. Some of my stuff worked that way, where the position 
of the sprite is calculated based on the clock, not unlike the way 
POV-Ray handles animation. There the RND was based on the clock also, as 
was the inputs (as in, "return the list of characters he typed up to 
time X").  It took some getting used to, but it was nice because you 
could combine things from different projects and get a nice visual effect.

For example, http://home.san.rr.com/dnew/FootNotes.html is written in 
this (custom) essentially-functional language, and a bunch of the bits 
are reused in lots of places (like, all the random movements are the 
same code, all the ovals are the same code, combining the two gets you 
the alien speaking, ...)  I could probably dig up the sources.

> How do you share a changing object among several other objects?

You put the image as one field of a structure (in C-speak), and the 
position as another field. When you want to move the sprite, you create 
a new sprite with the same image and a new position. The compiler avoids 
copying the actual image because it knows you can't change it so it's OK 
to share it with other sprites.



-- 
Darren New / San Diego, CA, USA (PST)


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.