7 Answers
7

In a pure functional language, you can't do anything that has a side effect.

A side effect would mean that evaluating an expression changes some internal state that would later cause evaluating the same expression to have a different result. In a pure functional language you can evaluate the same expression as often as you want with the same arguments, and it would always return the same value, because there is no state to change.

For example, a pure functional language cannot have an assignment operator or do input/output, although for practical purposes, even pure functional languages often call impure libraries to do I/O.

I/O is still possible in a purely functional language - you can treat the input stream as a list of characters, and similarly, you can return a (possibly lazy-evaluated) list of characters to be written as output.
– Anon.Dec 7 '10 at 22:27

3

In fact, early versions of Haskell worked exactly like that, though generalized to allow for more I/O actions than just reading and writing a single stream of characters.
– ephemientDec 7 '10 at 22:42

21

A functional language that merely calls impure libraries to do I/O isn't pure. Haskell is pure, and it can do I/O. The trick is to wrap up the I/O "actions" as immutable values. So "getChar" is a constant value of type "IO Char", and IO values can be composed into larger operations. The language has a notional interpreter that processes the IO value returned by the "main" function.
– Paul JohnsonDec 8 '10 at 6:38

16

This is a good answer, but I'm not sure it's the best one. As such, I'm surprised that it has the highest number of votes by far. Speaking from past experience, many people are confused about how a language like Haskell is claimed to be a pure functional programming language, and yet can still do something useful (e.g. I/O). This answer does nothing to clarify that.
– Daniel PrattDec 8 '10 at 12:21

9

On another note, despite the super-star level and deserved humongous reputation of Mr. Spolsky, I think he got a crucial detail wrong here, and that those up-voting his answer did so because he wrote it, not because it's right.
– BMephDec 28 '10 at 17:01

"Pure" and "functional" are two separate concepts, although one is not very useful without the other.

A pure expression is idempotent: it can be evaluated any number of times, with identical results each time. This means the expression cannot have any observable side-effects. For example, if a function mutated its arguments, set a variable somewhere, or changed behavior based on something other than its input alone, then that function call is not pure.

A functional programming language is one in which functions are first-class. In other words, you can manipulate functions with exactly the same ease with which you can manipulate all other first-class values. For example, being able to use a "function returning bool" as a "data structure representing a set" would be easy in a functional programming language.

Programming in functional programming languages is often done in a mostly-pure style, and it is difficult to be strictly pure without higher-order function manipulation enabled by functional programming languages.

Haskell is a functional programming language, in which (almost) all expressions are pure; thus, Haskell is a purely functional programming language.

"Pure" is just a modifier. You can just as easily have a pure logic programming language as a pure functional language. You should probably have said "Functional and pure functional are two separate concepts".
– Hugh AllenSep 4 '12 at 3:51

f is idempotent => f . f = f. You're statement equivocates the term idempotent with referential transparency. So even though you've gotten the semantics right, you really shouldn't be using the term idempotent that way.
– RussellStewartJul 13 '14 at 0:26

I think the statement "A pure expression is idempotent" is wrong. f(x): x + 1 is a simple increment function and is "Pure" because it does not have any side effects or state. Whereas, it is not idempotent because f(f(x)) != f(x). Whereas a function like g(x): x - x is both pure and idempotent. Because it always returns 0.
– Kartik SreenivasanMay 16 '17 at 10:09

A pure function is one which has no side effects — it takes a value in and gives a value back. There's no global state that functions modify. A pure functional language is one which forces functions to be pure. Purity has a number of interesting consequences, such as the fact that evaluation can be lazy — since a function call has no purpose but to return a value, then you don't need to actually execute the function if you aren't going to use its value. Thanks to this, things like recursive functions on infinite lists are common in Haskell.

Another consequence is that it doesn't matter in what order functions are evaluated — since they can't affect each other, you can do them in any order that's convenient. This means that some of the problems posed by parallel programming simply don't exist, since there isn't a "wrong" or "right" order for functions to execute.

Strictly speaking, a pure functional language is a functional language (i.e. a language where functions are first-class values) where expressions have no side effects. The term “purely functional language” is synonymous.

By this definition, Haskell is not a pure functional language. Any language in which you can write programs that display their result, read and write files, have a GUI, and so on, is not purely functional. Thus no general purpose programming language is purely functional (but there are useful domain-specific purely functional languages: they can typically be seen as embedded languages in some way).

There is a useful relaxed sense in which languages like Haskell and Erlang can be considered purely functional, but languages like ML and Scheme cannot. A language can be considered purely functional if there is a reasonably large, useful and well-characterised subset where side effects are impossible. For example, in Haskell, all programs whose type is not built from IO or other effect-denoting monad are side-effect-free. In Erlang, all programs that don't use IO-inducing libraries or concurrency features are side-effect-free (this is more of a stretch than the Haskell case). Conversely, in ML or Scheme, a side effect can be buried in any function.

By this perspective, the purely functional subset of Haskell can be seen as the embedded language to deal with the behavior inside each monad (of course this is an odd perspective, as almost all the computation is happening in this “embedded” subset), and the purely functional subset of Erlang can be seen as the embedded language do deal with local behavior.

Sometimes, the term “purely functional” is also used in a broader sense to mean languages that might incorporate computational effects, but without altering the notion of ‘function’ (as evidenced by the fact that the essential properties of functions are preserved.) Typically, the evaluation of an expression can yield a ‘task’, which is then executed separately to cause computational effects. The evaluation and execution phases are separated in such a way that the evaluation phase does not compromise the standard properties of expressions and functions. The input/output mechanisms of Haskell, for example, are of this kind.

I.e. in Haskell, a function has the type a -> b and can't have side effects. An expression of type IO (a -> b) can have side effects, but it's not a function. Thus in Haskell functions must be pure, hence Haskell is purely functional.

An IO function has the slightly different type a -> IO b, and indeed is a function which just returns an IO wrapped value.
– fuzDec 9 '10 at 1:21

@FUZxxl But that doesn't make IO pure (the compiler is lying about the purity). See my comments and links under Joel Spolsky's answer.
– Shelby Moore IIIDec 9 '11 at 21:37

@ShelbyMooreIII No one here is claiming that IO is pure (that would be rather silly). The compiler isn't lying, except insofar as you consider nonterminating programs impure.
– GillesDec 9 '11 at 22:33

@Gilles "No one"? I see 5 upvotes on Paul Johnson's comment under Joel Spolsky's answer, where Paul claims IO in Haskell is pure. Why are you mentioning "nonterminating"? Are you conflating the other page where I was writing about a bottom type? Seems you are confusing something that has nothing to do with the logic I am presenting about the IO monad in Haskell. Please explain.
– Shelby Moore IIIDec 10 '11 at 0:43

1

@ShelbyMooreIII You seem to be confusing computations of values of type IO a (the “immutable values” that Paul refers to), which are pure, with the execution of such values, which is effectful (Paul's “notional interpreter”). I mention nonterminating because strictly speaking, nonterminating are not referentially transparent, since the program has a different behavior if you evaluate them at least once or not at all. This has nothing to do with a bottom type; it is very much related with including a bottom value in every type.
– GillesDec 10 '11 at 1:11

As others have mentioned, the term "pure" in "pure functional programming language" refers to the lack of observable side-effects. For me, this leads straight to the question:

What is a side-effect?

I have seen side-effects explained both as

something that a function does other than simply compute its result

something that can affect the result of a function other than the inputs to the function.

If the first definition is the correct one, then any function that does I/O (e.g. writing to a file) cannot be said to be a "pure" function. Whereas Haskell programs can call functions which cause I/O to be performed, it would seem that Haskell is not a pure functional programming language (as it is claimed to be) according to this definition.

For this and other reasons, I think the second definition is the more useful one. According to the second definition, Haskell can still claim to be a completely pure functional programming language because functions that cause I/O to be performed compute results based only on function inputs. How Haskell reconciles these seemingly conflicting requirements is quite interesting, I think, but I'll resist the temptation to stray any further from answering the actual question.

You're misunderstanding how Haskell does I/O. In early prototypes, main was a pure function of a lazy stream of I/O replies from the world into a lazy stream of I/O requests to the world. Modern Haskell uses monads to make this easier to program, but the concept is still the same: a pure value describing a transformation to be applied to the outside, impure world.
– ephemientDec 8 '10 at 18:32

3

Haskell doesn't have functions which perform I/O. It has values (and functions that return values) that, when sequenced in the IO Monad in main, result in IO being performed by the runtime.
– ephemientDec 8 '10 at 19:39

2

Yeah, let's all ignore unsafe functions. My gripe is that, within the large safe parts of Haskell, "something that a function does other than simply compute its result" does not exist. Sure, if you include the execution of the runtime then some side-effects may happen, but you could replace the whole IO monad with ST, and your program would be pure and not know the difference.
– ephemientDec 8 '10 at 20:59

3

@Daniel: +1 for highlighting that it's a tricky point, but “how Haskell reconciles these seemingly conflicting requirements” is at the heart of the question. Also your second definition of side effects is flawed — it doesn't consider printing to be a side effect, for instance. The first definition is correct (within the limits of its simplification).
– GillesDec 8 '10 at 21:37

1

@ShelbyMooreIII Sure, it is a tricky point (one that you don't seem to fully grasp, either). Haskell isn't pretending to know the internal structure of the world; on the contrary, it goes through pains to know as little as possible about it. By the way, time is almost never continuous in models of computation.
– GillesDec 9 '11 at 22:32

Amr Sabry wrote a paper about what a pure functional language is. Haskell is by this definition considered pure, if we ignore things like unsafePerformIO. Using this definition also makes ML and Erlang impure. There are subsets of most languages that qualify as pure, but personally I don't think it's very useful to talk about C being a pure language.

Higher-orderness is orthogonal to purity, you can design a pure first-order functional language.