views:

341

answers:

3

Being relatively new to functional programming, I expend lots of energy wondering “is this the functional way to do things?” Obviously recursion vs. iteration is pretty straightforward and it’s obvious that recursion is the functional way of doing things. But take closures for instance. I’ve learned about closures using Lisp and I understand that closures are a combination of a function and an environment (sounds a lot like state and behavior). For instance:

(let ((x 1))
           (defun doubleX()
              (setf x (* x 2))))

Here we have a function doubleX that has been defined within the environment of the x variable. We could pass this function around to other functions and then invoke it and it will still be able to reference the x variable. The function can continue to refer to that variable, even if it is invoked outside of the environment where the variable has been defined. Many of the examples I’ve seen of closures look like this. Where setf is used to change the value of the lexical variable. This confuses me because:

1.) I thought setf was evil. Mostly because it causes side-effects and apparently they are also evil.

2.) Is this really “functional”? Seems like just a way of keeping global state and I thought functional languages were stateless.

Maybe I just don’t understand closures. Can someone help me out?

+9  A: 

You're right, using closures to manipulate state is not purely functional. Lisp allows you to program in a functional style, but it doesn't force you to. I actually prefer this approach because it allows me to strike a pragmatic balance between purely functional and the convenience of modifying state.

What you might try is to write something that seems functional from the outside but keeps an internal mutable state for efficiency. A great example of this is memoization where you keep a record of all the previous invocations to speed up functions like fibonacci, but since the function always returns the same output for the same input and doesn't modify any external state, it can be considered to be functional from the outside.

Kyle Cronin
+8  A: 

Closures are a poor man's objects (and vice versa), see

http://stackoverflow.com/questions/256625/when-to-use-closure

and my answer therein. So if you intend to use side-effects to manage state in your non-OO application, closures-over-mutable-state are indeed an easy way to do this. Immutable alternatives are "less evil", but 99.9% of languages offer mutable state and they can't all be wrong. :) Mutable state is valuable when used judiciously, but it can be especially error-prone when used with closures & capture, as seen here

On lambdas, capture, and mutability

In any case, I think the reason you see "so many examples like this" is that one of the most common ways to explain the behavior of closures is to show a tiny example like this where a closure captures a mutable and thus becomes a mini-stateful-object that encapsulates some mutable state. It's a great example to help ensure you understand the lifetime and side-effect implications of the construct, but it's not an endorsement to go and use this construct all over the place.

Most of the time with closures you'll just close over values or immutable state and 'not notice' that you're doing it.

Brian
No, they are not "poor man's objects", they are rather like a singleton.
Svante
A: 

Common Lisp and Scheme are not purely functional. Clojure is mostly functional, but still not purely. Haskell is the only language I know that is purely functional, I can't even mention the name of another one.

The truth is that working in a purely functional environment is very hard (go, learn Haskell and try to program something on it). So all these functional programming languages really what they do is allow functional programming, but not enforce it. Functional programming is very powerful, so use it whenever you can and when you can't don't.

Something important to know with the age that's coming is that anything that's functional is paralelizable, so it makes sense to avoid having side effects, or having in a smallest possible subset of your program as possible.

J. Pablo Fernández