3 ms·
I don't speak Rust well, but I can share my perspective from Clojure, where I tend to think in data. A program is a sequence of immutable functions taking inpu
by delegate 5y ago
I don't speak Rust well, but I can share my perspective from Clojure, where I tend to think in data.
A program is a sequence of immutable functions taking input from the world and reducing that to instructions to mutate the world (aka side effects). The world here can also be some place that stores state.
Ideally mutation is the last step of the pipeline, which takes the instructions and produces the side effects.
Or simply
input -> fn1 -> fn2 -> fnn -> mutate!
Where 'fn' are all immutable.
- Someone 5y agoThat model fits functional reasoning. It doesn’t fit all programs, though, as it doesn’t allow the input to depend on the _execution_ of the mutation instructions. Example: input “I step forward”, output “monster appears”, next input “I try to shoot it”. That second input wouldn’t be there if the output weren’t executed.
- marginalia_nu 5y agoOutputting and manipulating side-effects can be useful even in imperative code. I had real performance problems a while back attempting to build a very large file, my code could only produce the write instructions out of order and the file was too big to hold in memory, so what I ended up doing was writing writing instructions in radix-grouped batches to a bunch of temporary files, and then reading and evaluating them to build the large file. This seems counter-intuitive, as it more than doubles both the amount of data written to disk as well as adds a reading-step, but doing it this way means the data is written in a way the hardware can deal with a lot more efficiently. Sequential access to and from the instruction files (off a mechanical drive), and densely clustered writes to the big output file. (on an SSD, strictly sequential writes matters less than being in the same block) This reduced the runtime from several hours to like 5 minutes.
- themulticaster 5y agoI think it's always fascinating to find situations where counterintuitively it is faster to do more work. For example, it took me a while to realize that most of the it's actually faster to read/write compressed data overall - you'd think that reading from a disk and decompressing the data would be slower than just reading uncompressed data from a disk directly, but due to the vast difference in disk IO performance and CPU decompression performance it's almost always faster to perform disk IO compressed. I'm writing almost always since I'm not sure how the tradeoff looks for current high performance PCIe SSDs (or other storage devices with very fast IO).
- Rumudiez 5y agoYou missed the point where a program can take inputs over time. In your example, the program takes “step forward” and goes through the flows, eventually mutating state at the end, including redrawing the screen or prompting the user for their next input. The next input is based on the current state of the machine, and there can be as many or few valid state transitions as you, the programmer, would like to manage.
- Someone 5y agoWhat you propose requires some arrow leading (directly or indirectly) from mutate! to input. The model I commented on: input -> fn1 -> fn2 -> fnn -> mutate! doesn’t have such a loop.
- themulticaster 5y agoYour example isn't entirely clear to me - do you mean that “I step forward” and “I try to shoot it” are instructions in sequence? What exactly do you mean with allowing the input to depend on the execution of the mutation instructions? In any case, what I'm going for is that in both imperative and functional programming languages I would have a function/method like "handleInput" that takes an input and decides what to do with it. The difference would be that in a classical OOP setting handleInput would be a method of your GameState class [1] while in FP handleInput would look something like "Input -> (GameState -> GameState)", i.e. a function that takes an input value and returns a function that transforms the game state in some way (alternatively and equivalently, thanks to associativity/currying: a function that takes an input value and a current game state and returns a new game state). [1] I know, this obviously is a very contrived example, it'd only work for very simple games. Game programming patterns are interesting but not the focus here.
- yakshaving_jgt 5y ago> immutable functions That doesn't sound right.
- delegate 5y agoOh you're right, having coffee at the terrace while typing on the phone, I meant 'pure' functions which take and return immutable data structures.