42
votes

I've often heard that functional programming solves a lot of problems that are difficult in procedural/imperative programming. But I've also heard that it isn't great at some other problems that procedural programming is just naturally great at.

Before I crack open my book on Haskell and dive into functional programming, I'd like at least a basic idea of what I can really use it for (outside the examples in the book). So, what are those things that functional programming excels at? What are the problems that it is not well suited for?

Update

I've got some good answers about this so far. I can't wait to start learning Haskell now--I just have to wait until I master C :)

Reasons why functional programming is great:

  • Very concise and succinct -- it can express complex ideas in short, unobfuscated statements.
  • Is easier to verify than imperative languages -- good where safety in a system is critical.
  • Purity of functions and immutability of data makes concurrent programming more plausible.
  • Well suited for scripting and writing compilers (I would appreciate to know why though).
  • Math related problems are solved simply and beautifully.

Areas where functional programming struggles:

  • Debatable: web applications (though I guess this would depend on the application).
  • Desktop applications (although it depends on the language probably, F# would be good at this wouldn't it?).
  • Anything where performance is critical, such as game engines.
  • Anything involving lots of program state.
11
sum [ x | x <- [1..999], rem x 3 == 0 || rem x 5 == 0] Project euler problem 1 solved in Haskell. Now that's cool.Rayne
I don't see why desktop applications are a problem, apart possibly from a lower level of support from GUI builder tools and the like. "Lots of program state" may mean very little. In many cases you can replace seemingly complex program state with the right combination of functions, closures and continuations.Paul Johnson
Depends which definition of "functional programming" you are using. Do you mean purely functional as in Haskell or providing first-class lexical closures as in F#, OCaml, Scala, Clojure and even C# 3.0?J D
I just mean the functional paradigm in generalCarson Myers
I have to disagree with everything in your contra section. Functional programming (indeed, the paradigm) is great at web applications (Haskell+Happstack/Snap/Yesod, Racket+CPS, etc.). Haskell with FRP is better than anything I've ever seen for GUI/desktop applications, it just needs more developers to work on it. I regularly write blazingly fast Haskell programs for everything you can imagine (number crunching, simulations, AI, graphics, networking, etc.). Finally Haskell (again with FRP) is the best language for maintaining complex state. See stackoverflow.com/q/15467925/1978898ertes

11 Answers

13
votes

Functional programming excels at succinctness, owing to the existence of higher level functions (map, lfold, grep) and type inference.

It is also excellent at generic programming, for the same reasons, and that further increases the ability to express complex ideas in a short statement without obfuscation.

I appreciate these properties since they make interactive programming plausible. (e.g. R, SML).

I suspect that functional programming can also be verified more readily that other programming approaches, which is advantageous in safety critical systems (Nuclear Power Stations and Medical Devices).

11
votes

I would say that functional programming are suited for problem solving e.g. AI problems, math problems (this is far too easy), game engine but not too well suited for GUI and custom controls development or desktop application that requires fancy UI. I find it intuitive to think the following way (though it may be generalizing too much):

            Back-end   Front-end
Low-level   C          C++
High-level  FP         VB, C#
6
votes

Functional programming would be good for parallel programming. The fact that you're not relying on state changes with functional programming means that the various processors/cores won't step on eachother. So the types of algorithms that take well to parallelism like compression, graphical effects, and some complex mathematical tasks would also typically be good candidates for functional programming. And the fact that multi-core CPU's and GPU's are only growing in popularity also means that the demand for this type of thing will grow.

6
votes

It may not be directly tied to functional programming, but nothing beats unions in the design and implementation of data structures. Let's compare two equivalent pieces of code:

F#:

type 'a stack = Cons of 'a * stack | Nil
let rec to_seq = function
    | Nil -> Seq.empty;
    | Cons(hd, tl) -> seq { yield hd; yield! to_seq tl }
let rec append x y =
    match x with
    | Nil -> y
    | Cons(hd, tl) -> Cons(hd, append tl y)
let x = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))
let y = Cons(5, Cons(6, Cons(7, Cons(8, Nil))))
let z = append x y
to_seq z |> Seq.iter (fun x -> printfn "%i" x)

Java:

interface IStack<T> extends Iterable<T>
{
    IStack<T> Push(T value);
    IStack<T> Pop();
    T Peek();
    boolean IsEmpty();
}
final class EmptyStack<T> implements IStack<T>
{
    public boolean IsEmpty() { return true; }
    public IStack<T> Push(T value) { return Stack.cons(value, this); }
    public IStack<T> Pop() { throw new Error("Empty Stack"); }
    public T Peek() { throw new Error("Empty Stack"); }
    public java.util.Iterator<T> iterator()
    {
        return new java.util.Iterator<T>()
        {
            public boolean hasNext() { return false; }
            public T next() { return null; }
            public void remove() { }
        };
    }
}
final class Stack<T> implements IStack<T>
{
    public static <T> IStack<T> cons(T hd, IStack<T> tl) { return new Stack<T>(hd, tl); }
    public static <T> IStack<T> append(IStack<T> x, IStack<T> y)
    {
        return x.IsEmpty() ? y : new Stack(x.Peek(), append(x.Pop(), y));
    }
    private final T hd;
    private final IStack<T> tl;
    private Stack(T hd, IStack<T> tl)
    {
        this.hd = hd;
        this.tl = tl;
    }
    public IStack<T> Push(T value) { return new <T> Stack(value, this); }
    public IStack<T> Pop() { return this.tl; }
    public T Peek() { return this.hd; }
    public boolean IsEmpty() { return false; }
    public java.util.Iterator<T> iterator()
    {
        final IStack<T> outer = this;
        return new java.util.Iterator<T>()
        {
            private IStack<T> current = outer;
            public boolean hasNext() { return !current.IsEmpty(); }
            public T next()
            {
                T hd = current.Peek();
                current = current.Pop();
                return hd;
            }
            public void remove() { }
        };
    }
}
public class Main
{
    public static void main(String[] args)
    {
        IStack<Integer> x = Stack.cons(1, Stack.cons(2, Stack.cons(3, Stack.cons(4, new EmptyStack()))));
        IStack<Integer> y = Stack.cons(5, Stack.cons(6, Stack.cons(7, Stack.cons(8, new EmptyStack()))));
        IStack<Integer> z = Stack.append(x, y);

        for (Integer num : z)
        {
            System.out.printf("%s ", num);
        }
    }
}
4
votes

Some problems I find functional programming suited for:

  • concurrency
  • compilers
  • scripting

Problems that I personally find not so well suited:

  • web applications (but that's probably just me, Hacker News e.g. is implemented in LISP)
  • desktop applications
  • game engines
  • things where you pass around lots of state
4
votes

I find Haskell as well-suited for doing anything math-related. Not that this an actual professional project, but I made a sudoku solver and poker analyzer with it. Having a program that is mathematically provable is great.

As far as what it's not well-suited for is anything where performance is a priority. You have less control over the algorithms used, since it's more declarative than imperative.

4
votes

I disagree that FP cannot be used for web applications. I know that Paul Grahm and Robert Morris started Viaweb that used Lisp to deliver web applications. I think as you go closer to hardware (device drivers, kernel etc), one wants to use as low level language as possible. This is because if more abstractions are used then its harder to debug in case of errors. Have a look at article "The Law of Leaky abstraction" by Joel Spolsky.

3
votes

Actually, I like using pure functional code for problems that require managing a lot of state. Those kinda languages tend to provide the best mechanisms for the explicit handling of state, since they don't let you do it implicitly. Implicitly managing state might seem easier on the small scale, but once the state starts to get complex you run into trouble without the correctness guarantees you get from doing it the FP way.

2
votes

I find the simplicity of functional programming for math problems with matrix math to be absolutely beautiful, have a look at how these types of problems are solved in Scheme!

2
votes

I would say that functional programming will have trouble for the low-level stuff, operating system kernels, device drivers, etc.

I said "have trouble", not "cannot be used" (because of Turing equivalence, anything can be used for anything).

An interesting question is whether this problem is fundamental in functional programming (because physical devices have state) or if we can imagine systems-oriented functional programming language/environments. For instance, BitC is only partially functional (it relies a lot on mutability).

1
votes

Functional and object oriented paradigm have orthogonal strength. you could say functional programming has the emphasis on verbs and object oriented programming on nouns. Or, in more practical terms: Object orientation makes adding new Data simple while functional programming makes adding new tools simple. Both require changes in code to achive the other goal. You would like to read http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.18.4525&rep=rep1&type=pdf (Synthesizing Oject-Oriented and Functional design to promote reuse