Resolving the Time Paradox Implied by Functional Programs
softwarefordays.com
softwarefordays.com
This fact is unfortunate for OO aficionados who try to build programs by modelling the real world, because it leads them to build programs with the same problem. Whereas FP aficionados realise that even though there's no "undo" in the real world, we can enable it in our programs.
Only from the inside ;)
in that case, without adding impure statefulness, how does one differentiate between "a paused frame is being displayed" and "an intermediate frame of a playing video is being displayed"
--
then at the end, the example from elm looks great, but i see lots of impure state being generated (browser, model) or am i missing something?
A "paused" frame could be represented like Fi, Fi+1 ... Fi+N, etc; for every moment i..(i+N), F remains the same and is thus "paused." The thing that's tough to wrap your head around is our language is rooted in object-orientation however. "Pause" is less of a meaningful term when time is discretized. See also https://softwarefordays.com/post/fp-as-a-scientific-revoluti...
All functional programs (even if written in Haskel) have side effects - the CPU only has a certain amount of registers that can be used, for example, so any nontrivial program will be constantly overwriting them. That elm program however only exposes pure functions in user land, just like with a Haskel program
i guess what i was thinking was, if there was a ui, with a play/pause icon, and playing the video should cause the play icon to switch to a pause icon (because video is now "playing" so we want to be able to click it and "pause" the video) how do we represent that in a purely functional way?
since at any "timeless" instant, t1 vs t2 is just a frame1 vs frame2 issue at the language level (?), how in a purely functional world, would we determine that video is indeed playing and that icon should be swapped while playing vs not?
does user-interactive systems imply that there must inherently be some impurity?
Also putting it all together in writing here https://softwarefordays.com/post/functional-programming-and-....
In this^ blog I've included an interactive user interface that can be seen as purely functional, even though it's a stateful ATM program. I'm actually hoping that this blog could help teach someone what took me 2 years to finally realize. I think it could be worthwhile given your questions - if you take a look, please let me know what you think!
There's two way to do it. One that requires keeping the full history of events, and another which only requires keeping the next one (or next few) and the result of applying the last ones.
I'll start with full history. You'd have something like:
defn button-icon(click-events):
if is-even(count(click-events))
return paused
else
return play
With this, when the program starts, click-events has nothing in it, so when we call button-icon with it, it returns paused, if the user clicks the button, we call button-icon again and now there is one click event in click-events, so we return play. If user clicks again, there are now two click events and so we return paused, and so on.There is still state in the running program, something is remembering all clicks to the button, but your UI logic is pure.
Ok, now this is inefficient and requires lots of memory. Basically every new user action we recompute everything from the program start, and remember all prior actions. That's why there's the second approach. Instead we will do:
defn button-icon(current-button click-event):
if click-event
if (current-button = paused)
return play
else
return paused
else
return current-button
Now the running program won't remember the list of all click events from the program start, instead it'll remember the last result from the last call to button-icon and it'll pass that last result to button-icon the next time the user takes an action. This can be bootstrapped recursively or using fold.> There is still state in the running program, something is remembering all clicks to the button, but your UI logic is pure.
could this be solved by having the whole app be some kind of recursive function that passes the events as a list that gets appended to over time?
then it could remain completely pure?
You can keep extracting the IO out, but you can't get rid of it. So Haskell or Elm would basically do the "dirty impure" IO on your behalf, so in your code it wouldn't even seem like you're doing impure IO, but your running program still will, just it'll be done by the Haskell/Elm runtime on your behalf. Or if you're not using those languages, the best you can do is extract it to your top level function.
You have a paused "state" if that's relevant to you. But you can say "the video pauses at time t1" and "the video resumes at time t2", rather than restricting yourself to "the video is paused" or "the video is not paused".
Well then there is something fundamentally different about the video between T1 and T2 vs after T2. That is state - paused or playing. Word games don't change that.