
Reconsidering Functional Programming - twiss
http://prog21.dadgum.com/207.html
======
loganmhb
Along these lines, for me one of the things that makes Clojure stand out is
the careful thought that went into state, time and identity in the design of
the language. It removes mutability as a default without forcing you to be
purely functional all the way down, and gives you tools to manage state
changes in ways that are easier to reason about (though still not necessarily
easy of course).

------
kibwen

      > single-assignment "variables,"
    

It's a pet peeve of mine to see people disparage the phrase "immutable
variable" as a contradiction. A given variable's value can _vary_ each time
its function is called, or each time its program is run, without ever needing
to be mutated. In fact, in practice _most_ variables don't end up requiring
mutation, which was a surprise for me coming from traditional imperative
languages (not to say that mutation isn't valuable, but it makes more sense
for your language to make variables immutable by default rather than mutable
by default).

    
    
      </rant>

~~~
dukerutledge
This is why we call these things "values" not "variables"

~~~
mbrock
Those are different concepts. Variables have names, values typically don't.
500 is a value; foo is a variable.

~~~
seanmcdirmid
Values that have names are typically called objects (their identity isn't
structural). Named values are necessary for having mutable fields (I.e.
variables).

~~~
mbrock
Hmm, that doesn't sound right to me, at least not if "name" means "identifier"
in the conventional sense (like foo). For example, stack-based languages can
do field mutation without names.

~~~
seanmcdirmid
Depends if we are talking about local stack or global heap state. If you just
want to modify a register, then a locally bound name/index/stack pointer is
sufficient. If you want heap allocated aliased (shared) state, you need
globally unique names or addresses. The challenge is always with global state,
hardly ever with locally scoped state.

------
RootDynasty
In my opinion the most important part of functional programming is the purity
of functions. There is a great quote about this on one of the Clojure doc
pages

"If a tree falls in the woods, does it make a sound? If a pure function
mutates some local data in order to produce an immutable return value, is that
ok?"

Function purity enforces that mutations are localized to small areas of the
code, while maintaining composition.

~~~
ufo
For me, having first class functions with proper lexical scoping is enough to
start feeling functional. That might sound like nothing but its surprising how
few of the most popular languages get both of those right.

~~~
Kiro
What is proper lexical scoping? Does JavaScript get it right?

~~~
coldtea
No. Javascript gets it horribly wrong without "var", still terribly wrong with
"var", and somewhat better with "let".

~~~
Kiro
I don't understand what let has to do with functional programming though
(enclosing a variable within if () {} instead of function block etc). Do you
mind elaborating?

~~~
coldtea
The question wasn't about functional programming per se, but about lexical
scope.

"let" keyword in ES6 allows Javascript to have "lexical" style scoping (with
some caveats due to JS legacy).

That said, several ways of scoping a variable can be had in functional
programming. Have a look here for some more explanation with regards to Common
Lisp:

[http://stackoverflow.com/questions/463463/dynamic-and-
lexica...](http://stackoverflow.com/questions/463463/dynamic-and-lexical-
variables-in-common-lisp)

------
Ingon
I wonder if somebody have tried using a STM style approach to making games?

For a couple of LudumDares I did try (in java) and for the games I was able to
do it worked fairly well. Basically the drawing thread is seeing a frozen
readonly version of the world (and keeps 60 fps) while the update thread will
try to run simlation over readwrite version of the world. When the update
thread finishes it will "publish" the new state and start over. I have ever
wondered how it will perform at scale, maybe it will start braking apart if it
grows too much?

~~~
orbifold
It breaks down when you approach the hardware limits, i.e. for rts games with
thousands of units on the screen, particle effects and so on, or if you have
complex cad models in automotive applications. Essentially you then need to
minimize driver overhead and avoid data copying at all costs. In particular
you need to do memory mapped IO (using glMapBufferRange) between the GPU and
main memory as fast as possible. That is only possible if you do tripple
buffering with a ring buffer, at any given time one part of the buffer will be
in flight to the GPU, one will be processed by it and the third will be
modified by the CPU. You "publish" with synchronization (glFenceSync() and
glClientWaitSync()), see for example
[http://gdcvault.com/play/1020791/](http://gdcvault.com/play/1020791/).

In particular you have to organize all your world data in flat mutable arrays
because even on the CPU your data has to be presented in a way that avoids
cache misses as much as possible, this philosophy goes by "data-oriented
design", see for example
[https://www.youtube.com/watch?v=rX0ItVEVjHc](https://www.youtube.com/watch?v=rX0ItVEVjHc).

~~~
davexunit
This is all very low-level stuff, though. Functional systems are high level
abstractions typically erected on top of a low-level, imperative foundation.
Let's use the particle effects example: One can describe how a particle system
should behave using pure functions and immutable data whilst letting the
actual simulation and rendering be handled by a low-level system that does all
the dirty stuff necessary for speed.

~~~
Veedrac
I agree that it's potentially possible to make a functional layer on top, but
it still seems somewhat irreconcilable with the idea of STM.

------
zak_mc_kracken
> "At what point in the frame was this change made?" Some parts of the game
> may have looked at the original version, while others looked at it after the
> change. Now magnify the potential for crossed-wires by all of the
> destructive rewriting going on during a typical frame, and it's a difficult
> problem.

Not really, it's a pretty trivial problem and one of the least concerns of
game programming these days.

~~~
loup-vaillant
This is an _unsolved_ problem in a very high profile AAA _competitive_ game:
Starcraft II.

In Starcraft II, when 2 Protoss players order one of their templars to
move/cast a particular fatal spell to the other templar, then wait, you do not
get the expected double kill. Instead, when they get in range of each other
one templar casts the spell _first_ , kill the other, and survives.

Which templar lives and which dies depends on the order the units are
processed in the frame —arguably an implementation detail. To the players,
this is just plain unfair. Not a deal breaker for a hosts of reasons, but
still no good.

~~~
zak_mc_kracken
This is a pretty standard multithreading problem that has nothing to do with
mutability or immutability.

~~~
agumonkey
Mutability implies caring about order. I think that's why GP used this
example.

~~~
loup-vaillant
Indeed. This problem arises even in a single thread setting. Let's say 2 units
aim at each other, and in frame N, they are at range of each other. Here's
what should happen:

    
    
      - Unit1 kills unit2
      - Unit2 kills unit1
    

If you double buffer your actions properly, both unit will be dead at frame
N+1. If however you modify your data in place, this may happen:

    
    
      1. Unit1 kills unit2 => delete unit 2
      2. Unit2 no longer exists.  Unit1 lives.
    

Or, this may happen:

    
    
      1. Unit2 kills unit1 => delete unit1
      2. Unit1 no longer exists.  Oops.
    

Oops.

What definitely does _not_ happen is the double kill. StarcraftII can live
with that, but other games, like Frozen Synapse, would be broken.

~~~
agumonkey
What you call double buffer, other call transaction I believe, and it's a
system design. You have clear steps where information is gathered and rules
are applied.

In that case you take all the attacks, computes the damages, apply them and
prune the dead.

------
hartror
This is how the time travel mechanics of Braid were implemented. Record the
events, apply those events in a deterministic manner, and then reverse the
events to go backwards in time.

More generally this is pretty much the event sourcing pattern:
[http://martinfowler.com/eaaDev/EventSourcing.html](http://martinfowler.com/eaaDev/EventSourcing.html)

~~~
jblow
Not true, mostly. I recorded world state, not events. The one exception is
world 5 where I record events so that your shadow-universe guy can do things.

Event recording has a fair bit of history in games, especially as a debugging
technique, but I did not want to use it for rewind, considering it too fragile
and annoying, and probably too expensive and complicated (you would have had
to store world state anyway, to have something nearby to delta from so that
you don't start from the beginning of time every frame, so now you have TWO
systems: world state recording and event recording. Better to stick with one.)

~~~
Negative1
Can you elaborate on the distinction between world state and events? As in,
you don't capture user inputs but rather track all object positions and states
at all times? seems very inefficient that way.

Also, big fan! Great work on the new language/compiler livecasts and can't
wait for The Witness.

~~~
jblow
Exactly: I record the positions of all objects every frame (and other state
variables), not the inputs that generated them.

It is more expensive in terms of the amount of memory required, but it is much
less expensive in terms of the amount of CPU required, and CPU was ultimately
the biggest problem, so it seems I made the right decisions. Even on a
limited-memory console like the Xbox 360 you can rewind most levels for 30-45
minutes before running out of buffer. That is more than anyone ever wants to
do as a practical gameplay interaction.

Working on The Witness... it will be done ... someday not too long from now.

~~~
fnordsensei
Did you use deltas a la trie-based immutable data structures, or did you save
the entire state every moment? Did you save frame by frame, or did you save ON
the event, and then interpolate animations between the two states when
reversing?

~~~
nulltype
[http://gdcvault.com/play/1012210/The-Implementation-of-
Rewin...](http://gdcvault.com/play/1012210/The-Implementation-of-Rewind-in)

------
tuukkah
The writer monad gives you purely functional "printing".

~~~
ufo
I don't think the article really is about printing. He just uses printing as
an analogy to point out that you can calculate changes without altering the
simulation data during the calculations.

And changing topic, I am not a huge fan of how the Writer forces your code
into a monadic style. One of the things I enjoy the most when I program in
Ocaml instead of Haskell is being able to put printfs or mutable buffers
wherever I want.

~~~
dllthomas
Writer isn't really about printing. It's about emitting values, to be later
collected. That could very easily be state changes.

~~~
ufo
I know. But even then, I kind of like being able to append values to a mutable
buffer that is in scope without having to rewrite everything to use monads.

~~~
dllthomas
_" I know."_

Then I don't understand your earlier comment.

 _" But even then, I kind of like being able to append values to a mutable
buffer that is in scope without having to rewrite everything to use monads."_

We can agree to disagree, there.

~~~
ufo
What I was trying to say is that I think there is some virtue in being able to
add effects to your program without having to change the syntax you use. Its
nice to only have to use List.map and not have two incompatible map and mapM
functions.

This is not to say that I don't value extra static safety. I think there is
definitely room for languages that track effects without the syntactic weight
of monads and monad transformers.

~~~
dllthomas
Ah, that's the bit I understood, and about which I said we could agree to
disagree. To me, that reads like "I want to add new side effects and not
document them," but I think coding style comes into play in complicated ways
and it's not something I am eager to dig into right here, right now.

What I did not understand was your response of "the article wasn't talking
about _actually_ printing" to the suggestion of using Writer, despite your
knowing that Writer is not about actually printing, Writer being in fact a
good fit for what was described in the article, and the poster having quoted
"printing" in the first place.

------
dgreensp
I think there's a good insight here, related to Clojure's atoms and Facebook's
Flux.

If you start by making everything in your program 100% immutable and timeless,
how do you introduce any kind of time-dependence? A nice clean answer is that
there is a global clock, and when it ticks, everything changes.

~~~
javajosh
Time dependence is just like an async dependence (like waiting for a mouse
click) in that, in a profound sense, a program doesn't "know when it will
happen". The only time a program's state changes is with new information, and
the clock is just another source of information. (There's no reason why you
couldn't specify timeouts in "ticks" and give the user a button that
represented a "tick" such that they could advance the program.)

~~~
girvo
Interestingly, I'm building an app in Flux/React that lets you do exactly
that.

~~~
javajosh
Cool. It's a style I've been working with, too. I'd be interested to check out
your work.

------
Animats
That's an argument for single-assignment programming, of which functional
programming is a subset. There's nothing wrong with named values; it's mutable
variables that are the problem.

Both Go and Rust encourage single-assignment programming, with ":=", "let",
and automatic type inference for assignments. C++ has had "auto" for years.
The trend is towards single-assignment as a programming style. Declaring named
values without initializing them is so last-cen.

Single-assignment programming is a bit more powerful than a pure functional
style; you can use a value more than once. It's the difference between a tree
and a directed acyclic graph. If you have code that does something imperative,
talking to the world outside the program, trying to hammer that into a pure
functional form is like pounding a screw.

It's also nice to have named variables when reading a program.

    
    
       f(g.h(f2(g2(x))))
    

provides little information about why someone was doing that. When those
intermediate results have names, it's somewhat more clear.

~~~
the_af
I assume you've never read anything written by Tony Morris on this matter :)
He argues that identifier names are one of the _least_ useful tools in
understanding programs: [http://tonymorris.github.io/blog/posts/identifier-
names/](http://tonymorris.github.io/blog/posts/identifier-names/) (his tone
might be a bit grating, but he knows his subject).

In any case, I'm puzzled... why do you think writing in a pure FP language has
anything to do with not naming your variables?

BTW, I'd say the opposite of your initial claim is true: single-assignment is
the subset of FP, not viceversa. There's way more to FP than immutability, and
in fact there are FP languages which allow (controlled) mutation.

~~~
bandrami
Unfortunately "functional" is coming close to being the Next Big Idea, which
means it stops meaning anything specific. If you look at unlambda[0] as the
kind of Platonic ideal of functional languages you might see what GP is
talking about.

It lacks any facility for bindings because any binding is a storage of state.
Roughly, since you _can_ refer to every function and value literally, the idea
behind unlambda is that you _should_.

(Note that by this way of looking at things, closures are not "functional" at
all and are in fact embeddings of imperative mini-languages.) Historically,
closures were more or less developed by accident as LISP codified its scoping
rules; in that sense their presence isn't particularly indicative of
"functional ness"; it's just that using them requires a GC and 40 years ago
only functional languages had one.

[0]
[http://www.madore.org/~david/programs/unlambda/](http://www.madore.org/~david/programs/unlambda/)

~~~
the_af
I agree there is no widely accepted and formal definition of "functional".

Thanks for the link! I didn't know about Unlambda.

A couple of remarks though: by the author's own admission, Unlambda is not a
purely functional language, when using the accepted terminology. The author
then goes on to introduce what he acknowledges to be _nonstandard_
terminology, so I'm not sure what this says about closures being functional or
not under more mainstream definitions. Furthermore, Unlambda is a
_purposefully obfuscated_ language! Not sure how it is relevant for the
purpose of my post or the OP's :)

Thanks anyway for the link, it's interesting.

------
ajuc
Immutability gives you elegant command-query separation, and it's sometimes
useful (for example you can use the same function in physics, and in AI to
predict where player will be in 5 frames). Of course you pay with performance.

I wonder if keeping a tree of game states in persistent variable (like Clojure
datastructures) could help with that.

We could keep the current state as a root of game states tree, AI code will
calculate possible future states a few steps ahead (these future states would
mostly share memory with parent and sibling states, and if we predict n frames
forward AI can start in each frame from states in step t+n-1 and calculate
their immediate kids only). This is trivialy parallelizable BTW.

And in each frame game engine would move the tree root to one of the kids
depending on player action, culling the previous root and the branches not
taken from the tree.

------
marssaxman
I took a stab at solving this problem with a programming language called
Radian: [[http://www.radian-lang.org/](http://www.radian-lang.org/)]

It is based on the observation that SSA is functional programming, and there
is a well-defined process for transforming imperative code into SSA, so why
not reverse the process and develop a functional language with imperative-
looking, Python-like syntax?

The goal was to automatically extract parallelism from for-loops, internally
converting them into map-reduce processes which could be spread across
multiple cores, and that worked out pretty well. In absence of a marketing
effort, however, a userbase never developed, and I haven't done any work on
the project in a couple of years.

------
dfbrown
I think the simplest way to do stuff like this is to build up an iterated copy
of the previous state and once done replace the old state with the new one.
Iterating isn't modifying the current state, it's generating the next state
from the current one.

------
hhandoko
Interesting premise. However, isn't what the author described is similar to
event-sourcing?

------
yzzxy
I think this is roughly how demos (in Quake, et al) are recorded. I think most
demos also include the state introduced by RNG if the game involves that. It's
interesting to think about that idea with relation to functional programming.

------
jarcane
I am a great lover of functional programming, so much so as to seek out and
find a summer job in Clojure this year, and to have written my own functional
Lisp dialect.

Lately though, as I've been weighing engine options for a CRPG project, I have
become increasingly skeptical of its applicability or utility to games.

The simple point of the matter is that games are humongous state machines, but
even more importantly, humongous state machines that are _performance
sensitive_.

The standard approach so far has been to simply deal with this either
monadically or atomically, having some big state object that gets passed
through each cycle, copied again and again with every frame. This is all well
and good when the full extent of your game state is a handful of blocks and a
paddle, but stop and think how many, say, console-style RPGs you've seen done
in functional languages to completion.

In the Pokemon games, there is a move called Defense Curl, that increases the
users defense. Simple enough. Then in the second gen games, it was very
silently given another effect: there is a particular attack move whose damage
is doubled if the user has previously used Defense Curl in that fight. In the
third gen, this was done again for an additional move that, at the time and
for three more iterations of the series, was only available to a _single
character_.

That is an incredibly specific state detail. And that's just _one_. The entire
game is filled with little quirks and mechanical details like that. There are
over 600 moves in the game, many with other unique effects, not to mention the
700+ creatures, almost 200 abilities, plus an entire hidden second stat system
with the IVs.

Try passing a state object containing all the flags you need to keep track of
_that_ 30 or 60 frames a second.

Is it any wonder then that you see so little done with FP languages that isn't
just clones of old arcade games? I know of _one_ company working on an A-level
game in Haskell. Beyond that, I've seen a couple Quake 3 ports and a whoooole
lot of unfinished projects.

I'm just not convinced it's up to the task yet, and the research and
theoretical end still seems to focus on trivial toy examples instead of full-
scale projects that are on a whole other order of magnitude from Pac-Man. I
seriously start to wonder how much of the learning so far and the 'obvious'
patterns and solutions that seem to already just be accepted dogma, really
have anything to do with real-world games programming in the large.

Maybe Wayward Tide will finally release source and prove me horribly wrong
here, or Elm will indeed prove as promising as it looks when extended beyond
simple browser toy experiments, but in the meantime I'm veering hard back to
commercial, traditional engines instead.

~~~
dllthomas
_" Try passing a state object containing all the flags you need to keep track
of that 30 or 60 frames a second."_

You can structure your data such that you only need to rewrite a portion of
it, based on what changed. I couldn't more highly recommend "Purely Functional
Data Structures" by Chris Okasaki.

~~~
dllthomas
Following up on this...

With regards to the Pokemon example given, I can think of two good ways to
encode it:

First, simply a bunch of single-bit flags, one per move per competitor. Each
turn, for move tracking, we update at most one bit in one of these arrays by
copying the array and updating a pointer. We can track 1000+ moves, and only
need to copy 128 bytes. You can do thousands of comparable things and still be
done in a single frame.

Second, a list of turn information. A move could ask arbitrary questions about
the history of the current fight by walking the list. An append-only list
trivially has an immutable sublist, and you only need to "pass" a single
pointer. Walking the list should be trivially possible well inside a single
frame, provided you don't have many thousands of turns in a single fight.

All that leaves aside the fact that you don't actually need to fit your world
updates in a single frame render - you can interpolate/extrapolate. This is
especially easy in a turn-based game like Pokemon, where it mostly consists of
"smoothly progress through the same animation".

------
journeeman
Isn't the author basically saying, an iterative process (process as in
procedure-semantics; like the word is used in SICP) is better than a recursive
process?

