-1

I was asked this question in an interview recently. I could not get the right answer.

When you repeatedly call a function in a procedural language(like C) and a functional language(like haskell) with same arguments in which language you might get a different result ? I read on [this] (What is the difference between procedural programming and functional programming?) post that pure functional languages will always result in the same answer. Why is this so for functional languages and not for procedural languages?

Community
  • 1
  • 1
  • The answer is more theoretical than practical, but if you want a practical example, think about multi-threading and race conditions for shared data as one of the side-effects that can happen in a procedural paradigm. A pure functional programming tool would be designed to avoid such conditions. You might find this link useful: http://www.quora.com/Why-does-functional-programming-favor-concurrency – Jorge Torres May 17 '15 at 04:55
  • The way i understand it is functional languages try to use [pure functions](http://en.wikipedia.org/wiki/Pure_function) plus they are declarative so you tell them _what_ you would like to do and the compiler figures out how and since it's philosophy is to use pure functions it does it that way with no side effects while procedural languages are imperative, you tell them _how_ to do something, they just follow instructions step by step and don't care if it's a pure function or not. – James May 17 '15 at 05:21

3 Answers3

4

In imperative programming, functions are allowed to have side-effects, such as modifying the value of variables, writing to files, accessing the network, etc. The second time the same function is run, it can detect the previous side effects and return something different. A simple C example is:

int i = 0;
int foo() {
  return i++;
}

Calling this multiple times will generate different numbers. As another example:

int foo(int *p) {
  return (*p)++;
}

Even if you call the above with the same parameter, i.e. the same pointer, the result will be different because of the increment.

In pure functional programming, side effects like i++ are forbidden by design. In this way, the output of the function must depend only on the value of its arguments. E.g. if in Haskell we have a function f with type Int -> Int, we can be sure that f 3 will always return the same integer at every call.

Well, the above is not entirely true -- a program eventually has to do some I/O, or would be meaningless. Because of this, side-effects must be available in some form. In Haskell, functions with side effects are actually allowed, but their type must tell these are not pure functions. E.g. if function g has type Int -> IO Int, then it can perform I/O and have side-effects: running print =<< g 3 can print different values every time, just as in imperative programming.

So, summing up, in pure functional programming functions having side effects have a different type from functions who do not. Often, in a well-designed functional program, I/O and side-effects are rarely needed, and pure functions comprise the vast majority of the code. Because of this, sometimes we say that "pure functional programming forbids side effects", since most of the code is written under this constraint.

chi
  • 111,837
  • 3
  • 133
  • 218
3

Purely functional languages operate such that the same input always produces the same output, with pure functions having no side effects. However, in procedural or not purely functional languages, such as C, side effects can occur, such as a pointer being modified, or other outside factors such as time or file I/O. Even Haskell can do file I/O. Therefore if Haskell with I/O is a purely functional language, then C and the cpp are purely functional, too.

Take this C program as an example:

#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif

#include <stdio.h>
#include <time.h>
#include <unistd.h>

int get_num(int n)
{
    usleep(1100000);
    return (time(NULL) - n) % (n / 10);
}

int main(void)
{
    int i;

    for (i = 0; i < 10; i++)
        printf("%d\n", get_num(4242));

    return 0;
}

We take a constant parameter of input, 4242, to get_num. After the arbitrary math, it is because of the time factor and the sleeping that the same input does not produce the same output in this procedural language.

Run at one time, we get:

247
248
249
250
251
253
254
255
256
257

And run later, we get:

270
271
272
273
274
275
277
278
279
280

In most C, side-effects abound. In a purely functional language though, such side-effects would not be present or possible.

jfjhh
  • 43
  • 6
1

To clarify further, it is not so much a property of a language. No imperative language forces you to write side effecting procedures only. It is also perfectly possible to write in a pure functional style, though it is not explicitly supported.

Whereas in a pure functional language, there simply are no language constructs that allow you to modify variables, access globally visible storage etc. Thus it is a bit exaggerating to say that pure FP languages "forbid" impure functions - rather, there is just no way to write one in the first place. Note that even functions like:

printTwice x = do {putStrLn x; putStrLn x}

are not impure. Application of printTwice results in an IO action. You can do this many times, put the result in lists or tuples and pass them around, this is all pure. Specifically, there is no difference between:

 twoActions = (printTwice "hello", printTwice "hello")

and

 twoActions = (a,a) where a = printTwice "hello"
Ingo
  • 36,037
  • 5
  • 53
  • 100
  • It should be noted that even though `printTwice` is an pure function, it can be easily made `impure` because of the `IO` type constructor. – Sibi May 18 '15 at 12:25