new_game_state = simulate_a_frame(old_game_state, user_input, time_delta)
So of course it's possible. Whether it's practical is another question.
new_game_state = simulate_a_frame(old_game_state, user_input, time_delta)
So of course it's possible. Whether it's practical is another question.
This abstraction was almost fully stripped away by the compiler. Since the original Machine object is no longer required when the step function returns from executing an instruction, and since the size of the emulated RAM never changes, the compiler can, for example, represent the list of RAM values as an array, and mutate the array in place and internally just keep track of the pointer to the mutated object and return that. It isn't necessary to copy most of the data structure most of the time.
minihs keeps itself small, uses a stack of copies of source to implement []. Whereas the larger version parses the source to a vector of opcodes (which collapses repeated +-<>) & includes a jump table
Although in practice "purely functional" programming is a bit silly here. The point of PacMan is all the IO which is fundamentally all side effects. There are a lot of practical compromises that would be called "functional" like storing all the major state of the game in a big array (something like [turn1, turn2, turn3, ...]) and then implement a turnX -> turnX+1 animation function.
The fundamental insight of the functional approach is implementing a frame->frame function was already something that implicitly had to be done to make the game. If it is an explicit function then debugging it is easier. Because the input can be saved. No extra work is needed.
In fact, the point of a huge proportion of programming is IO and is "all side effects." It's still possible to adopt a functional style for internal calculations (and in fact this helps to decouple components and makes testing much easier, at the expense of relatively negligible copying overhead, so it's worth doing) but once you get beyond your internal toolkit and start actually trying to test the whole system, you're interacting with the outside world.
To be sure, I don't think this is a correct interpretation, but I do think it may play a role in the difficulty of getting people onboard with FP.
Input is an obvious example, as it's impossible to predict the value of an input.
Output is less obvious, but there is uncertainty like whether the filesystem is full.
The original Haskell style was to have a World object that was an input to every non-pure function.
Do you mean this more abstractly or literally? In the example of PacMan, for every frame, the only possible input is nothing, left, right, up, or down. So you are be able to predict it is going to be one of those five, though not which one.
>> Input is an obvious example, as it's impossible to predict the value of an input.
> though not which one
Literally.
So because the possible input is not just a single value, it is not predictable. It doesn’t matter if the input was limited to a set of two values, or infinite, it is literally not predictable so therefore we don’t know the future state of the program?
If you model the controller input as a function parameter, that's just a state argument, and FP can handle it declaratively just fine without having side effects.
Some languages make this easier to model than others, and some make doing so in a pure style easier, eliding real-world side effects like RAM access, GPU, etc.
Once you are comfortable with this concept, functional languages make a lot more sense, if you don't get lost in symbol soup.
Edit: a simple Google search for "functional core imperative shell" brings up many writings on the concept.
"Effects" (without the "side") usually means the effect is modeled as a type/value that is returned by the function.
Side effects are the opposite of pure functions. A function with side effects will mutate global state, a function without side effects will not (it will simply return a value).
https://en.m.wikipedia.org/wiki/Side_effect_(computer_scienc...
It's the opposite, for FP, OOP, imperative, that is the part of the program which is easiest.
FP is about managing the difficult parts, and so is OOP. They just have different approaches, and note, many mainstream languages are incorporating FP concepts quite readily now.
It's also not just a syntax difference, mainstream languages are embracing immutability more and more, often as a default.
The point is that calling FP academic is a tired trope and even if it is far from the dominant paradigm, there is clearly practical lessons to be learned whatever paradigm you program in.
A Haskell program covered in piles of monads to abstract all state away still follows the functional core imperative shell pattern, because the runtime is the imperative shell. This doesn't make such a thing desirable for other languages.
The practical lesson I learned from dabbling with functional programming in academia is that functional programming is often impractical and does not offer any of the purported benefits of better code.
A shell is not more imperative than a processor - both are Turing machines, a completely functional mathematical object. Seeing them as imperative is a semantic interpretation of the people watching it, not an inherent property.
This is what state monads are doing anyway under a hidden syntax, and for simple cases it may be easier that building a full dedicated monad.
Most mainstream languages are old, they can't be immutable my default without breaking backwards compatibility. I'm talking about the design direction of languages that are already based on mutability. For example, Java added Records which are immutable, as well as overhauling the date/time api with an immutable version.
> This doesn't make such a thing desirable for other languages.
I've used this pattern in other languages, none of this is a silver bullet that makes software engineering easy; but I do find it makes some code much easier to test and reuse.
But "imperative" has such bad mouthfeel that I had to swear it off altogether.
Most modern PC games/engines have a really good instant quicksave system which dumps the entire world state very quickly.
I confess that sometimes things do, in fact, get a ton easier if you expand your abstraction out such that you are abstracting the whole board, and not a bunch of individual pieces. That comes with its own set of road blocks, though. In particular, game worlds are a lot bigger now than they used to be.
How far away are we from being able to represent the GPU state and rendering instructions with simple datastructures ready to be submitted wholesale to the driver?
And then render based on delta and interpolate movements.
Using a time delta would give different results when doing non-linear stuff. Like applying forces. It's different to apply "force * dt" vs doing "force * 0.5dt" twice. Also if you use a big dt you could end up going through walls or similar. So therefore the physics engine should run at defined ticks in most instances, or it will behave differently based on framerate.
And I can’t think of any reason why you’d combine them.
Recording it is still command driven but trying to give an entire app scene in one go is really messy. We tried this internally on our gpu before Vulkan.
I imagine that comes down to how smart the compiler is.