Search code examples
clojurefunctional-programmingstateimmutabilitypurely-functional

Functional programming with clojure, avoiding mutable state


So, my question is about whether I can avoid mutable state in a particular action my program needs to do.

Some context: About a week ago I decided to learn to program in Clojure, to teach myself functional programming. (By day I work as a web developer using mainly C#.

So in my experience the best way to learn a language is to start with a project. I chose to create something that I needed anyway, a small tool to read text snippets out of an XML file and then do some find-and-replacing in other text files (and detecting inconsistencies.

So I'm up to the part where I've parsed the file into a list of maps that I need, and here's the problem: the way I see it, I can pass around my data between functions as much as I want, at some point there's nothing to do for my program. And then when the user clicks a (javax.swing-button, my program will have forgotten everything.

How would a functional programmer solve this?

Possible solutions I came up with:

-Monads. (Great for building complexity but still disappear when the functions stop executing.

-Read the file from disk again everytime the user clicks a button: seems silly.

-Store the contents of my file within my form controls. Seems like cheating (and also just wrong.

-When a file is parsed, create a closure with references to the resulting datastructure, and install this a the new event handler(s) : seems like cheating and just generally a strange (but interesting) thing to try.

Who can tell me if I've identified this correctly as a situation where I can't do without a ^dynamic var?

Any pointers will be greatly appreciated.)))))

Edit: I'm not asking for for code examples, just a yes or no answer would do, and maybe a hint on what to look up next, to the question: is there a way for a clojure program to remember some data it computed, in idle state (until next java event handler gets fired), without using a global variable, atom, ref, or agent?

And the reason I'm asking is that I want to learn to program in a functional style the proper way, and I'm basically checking if I'm not going off track.

Thanks for all the useful responses so far, definitely got tips on books to read, that's always nice.


Solution

  • The Clojure-specific answer to your question is almost certainly not to use ^dynamic, but to use an agent, an atom, or refs.

    But I believe that your question is more of a philosophical one than practical? This interview with Simon Peyton Jones is my favourite explanation for this question. A pure (for the purest sense of pure) functional program has no side-effects and is therefore useless. As Simon says in the interview, however, functional languages all provide ways to introduce limited, controlled side-effects in such a way as to avoid polluting the purely functional aspects of a program. Haskell does that through its type system (monads, monoids, and category theory). Clojure does it through agents, atoms and refs. Elm does it through signals. Erlang does it through processes and message queues. And so on...