All programs are pipes from IO to IO or from one state to another state. Purity lives in the pipes, impurity lives in the IO nodes between the pipes. The goal is to keep the impurity as small as possible and have most of your logic live in the pipe, as combinators are the most composeable primitive. I also never said FP is the one right answer. Most programs need to modify state. In FP everything is immutable so your program cannot be pure FP in most cases. What I am saying is to segregate state and IO from logic. Example:
void addOneToState()
can be broken down into int addNTo(int n, int m)
void changeStateTo(int x)
I have split the code above into a method that is devoid of logic and only updates state and logic that lives as a stateless combinator. All programs are made from a series of pipes and tubes. You just need to find the pipe and modularize it and seperate it from the parts that can't be pipes.>At that point, bundling the data to the functions is warranted.
It's never warranted. There is no benefit. Whether you couple it or uncouple it from data the logic still exists, the only difference is coupling. Adding coupling does not improve your code in any other way other than adding coupling.
>And if you're going to say "don't structure the data that way", well, there are times when that's the nature of the problem, not just the nature of the program to solve the problem.
There is no data structure that has to be coupled with logic. However you structure your data it can always be decoupled from logic. Always.
>where your program has state, and there are multiple parts to the state, and those parts have to be kept in sync with each other.
This doesn't change anything.
State makeNewState (State oldState) {
newY = addNTo(oldState.y, 1)
return New State {
x = oldState.x
y = newY
somethingToBeInSyncTo = newY
}
}
void updateState(State x)
y is still in sync with somethingToBeInSyncTo.