You use closures as you would in a language with mutable variables. The difference is obviously that they (usually) can't be modified.
The following is a simple example, in Clojure (which ironically I'm writing with right now):
(let [a 10
f (fn [b]
(+ a b))]
(println (f 4))) ; Prints "14"
The main benefit to closures in a case like this is I can "partially apply" a function using a closure, then pass the partially applied function around, instead of needed to pass the non-applied function, and any data I'll need to call it (very useful, in many scenarios). In the below example, what if I didn't want to call the function right away? I would need to pass a
with it so it's available when f
is called.
But you could also add some mutability into the mix if you deemed it necessary (although, as @Bergi points out, this example is "evil"):
(let [a (atom 10) ; Atoms are mutable
f (fn [b]
(do
(swap! a inc) ; Increment a
(+ @a b)))]
(println (f 4)) ; Prints "15"
(println (f 4))); Prints "16"
In this way you can emulate static variables. You can use this to do cool things like define memoize
. It uses a "static variable" to cache the input/output of referentially transparent functions. This increases memory use, but can save CPU time if used properly.
I have to disagree with being against the idea of having a state. States aren't evil; they're necessary. Every program has a state. Global, mutable states are evil.
Also note, you can have mutability, and still program functionally. Say I have a function, containing a map over a list. Also say, I need to maintain an accumulator while mapping. I really have 2 options (ignoring "doing it manually"):
- Switch the
map
to a fold
.
- Create a mutable variable, and mutate it while mapping.
Although option one should be preferred, both these methods can be utilized during functional programming. From the view of "outside the function", there would be no difference, even if one version is internally using a mutable variable. The function can still be referentially transparent, and pure, since the only mutable state being affected is local to the function, and can't possibly effect anything outside.
Example code mutating a local variable:
(defn mut-fn [xs]
(let [a (atom 0)]
(map
(fn [x]
(swap! a inc) ; Increment a
(+ x @a)) ; Set the accumulator to x + a
xs)))
Note the variable a
cannot be seen from outside the function, so any effect it has can in no way cause global changes. The function will produce the same output for each input, so it's effectively pure.