2

I have watched the talk of Robert C Martin "Functional Programming; What? Why? When?" https://www.youtube.com/watch?v=7Zlp9rKHGD4

The main message of this talk is that a state is unacceptable in functional programming. Martin goes even further, claims that assigments are 'evil'.

So... keeping in mind this talk my question is, where is a place for closure in functional programming?

When there is no state or no variable in a functional code, what would be a main reason to create and use such closure (closure that does not enclose any state, any variable)? Is the closure mechanism useful?

Without a state or a variable, (maybe only with immutables ids), there is no need to reference to a current lexical scope (there is nothing that could be changed)?

In this approach, that is enough to use Java-like lambda mechanism, where there is no link to current lexical scope (that's why the variables have to be final).

In some sources, closures are meant to be a must have element of functional language.

LancerX
  • 1,211
  • 7
  • 23
  • 40
  • 3
    Keep in mind, regardless of the paradigm you're coding in, you will **always** have state; **always**. State isn't evil, it's entirely necessary. What is evil is mutable, global states; or states that attempt to encompass too much (God objects). – Carcigenicate Oct 17 '16 at 14:47
  • OK. This guy explains what is closure. https://www.youtube.com/watch?v=7aYS9PcAITQ#t=18m13s I think that, in his example very_local_variable is that 'evil' state. Because calling c1() first, second an so on, will be not identical. Each call will 'change the world'. So... maybe this second example (with closure explanation) is not very correct? – LancerX Oct 17 '16 at 15:03
  • 1
    If the state being mutated is outside of the function, yes, that could considered evil. Look at my new edit in my answer. You *can* have mutability without effecting a global state, and that isn't evil since it's not changing anything outside of the function. The function is still effectively functional and referentially transparent. – Carcigenicate Oct 17 '16 at 15:06
  • 1
    @LancerX Yeah, the counter example is not the best example for functional programming, but it helps immensely to understand that the closure closes over the variable which is *shared* between the invocations. In purely-functional programming, sharing is optional because it doesn't make a difference for the result (only for performance). It's a simple demonstration of the concept and its usefulness, albeit in an impure language. – Bergi Oct 17 '16 at 15:09
  • …and an example that doesn't evoke "but I could have done this without closures" reactions might be harder in a pure language. – Bergi Oct 17 '16 at 15:16
  • If you didn't have a closure, where would you store values that you're going to need later? – molbdnilo Oct 18 '16 at 14:25

2 Answers2

3

A lexical scope that can be closed over does not need to be mutable to be useful. Just consider curried functions as an example:

add = \a -> \b -> a+b
add1 = add(1)
add3 = add(3)
[add1(0), add1(2), add3(2), add3(5)] // [1, 2, 5, 8]

Here, the inner lamba closes over the value of a (or over the variable a, which doesn't make a difference because of immutability).

Closures are not ultimately necessary for functional programming, but local variables are not either. Still, they're both very good ideas. Closures allow for a very simple notation of the most(?) important task of functional programming: to dynamically create new functions with specialised behaviour from an abstracted code.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
2

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.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
  • One might argue that the state in your example *is* evil, since the function `f` is no more referentially transparent. – Bergi Oct 17 '16 at 15:11
  • Yes, the one `emulating` static variables is evil. I was showing that it could be used within a functional language to some possible benefit, but no, this is far from an ideal use case. That's why I added the other examples to show that a local mutable state is also potentially useful, but not harmful. – Carcigenicate Oct 17 '16 at 15:13