views:

1222

answers:

10

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.
+7  A: 

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).

Alex Brown
Type inference is not a property of functional programming.
Chuck
http://en.wikipedia.org/wiki/Type_inference"It is often characteristic of — but not limited to — functional programming languages in general."An introduction to functional programming systems using Haskell By Antony J. T. Davie 1996:"One of the most important ideas of Functional Programming Languages is that of automatic type inference"Where's your evidence?
Alex Brown
That a Haskell author things that type inference is an important property of FPL is hardly surprising. Without a static type system it is even shorter. Think of APL - and, no, APL programs are not only short because of the identifiers.
Rainer Joswig
Not all functional languages have type inference and there exist imperative languages that have type inference.
trinithis
+3  A: 

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
boxofrats
I find scripting with FP kind of weird. Scripts all usually small enough that state won't bite you.
Zifre
If I say scripting in FP, I think especially Scheme and LISP. A widely used example is Emacs LISP. Javascript originally started out as Scheme and it shows here and there.
boxofrats
+4  A: 

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.

Steve Wortham
-1. You're implicitly referring to purely functional programming (avoiding side effects as opposed to using first-class functions) which is a total disaster in the context of performance and parallelism is all about performance.
Jon Harrop
AFAIK Haskell is about the same speed as most better programming languages, so this definitly doesn't counts.
FUZxxl
+2  A: 

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!

mduvall
+3  A: 

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.

Jacob
I don't quite agree. To achieve performance, you often have to break past the abstractions and figure out how various high-level constructs are actually implemented, from the hardware's perspective. Certainly Haskell is further abstracted, but if you put the effort in to learn the particulars of GHC's implementation, optimizing for performance is quite doable. Other functional languages like Lisp and SML have much simpler execution and memory models, and can be "tuned" just as easily as traditional imperative languages.
ephemient
But, see, that's part of the problem: you mentioned GHC. Despite the fact that it's my favorite Haskell implementation, there are others out there and potentially more to come. What's more, there's no guarantee that the implementation of a core library function for one implementation will remain the same across versions.This is why I think that functional languages are best used where the "what" is more important than the "how."
Jacob
Given that there's no other high-performance Haskell environment out there, I don't think targeting GHC is too unreasonable... People specifically target GCC or ICC or MSVC or etc. when trying to optimize C code, do they not?
ephemient
Fair enough; but you have to admit that C code translates more directly to machine instructions than Haskell does, so it can be more obvious how to optimize your C algorithms. But of course, having to put more thought into your code comes with the territory with Haskell, when you're starting out. In most cases you don't have to worry about speed anyway, so the elegance is well worth it.
Jacob
Theoretically, a purely functional programming language should be faster than an imperative one in a lot of cases because a lot more optimizations are possible with it. But GHC isn't as mature as, say, GCC, so not all optimizations have been put in place. Also, Haskell is fairly high level so that also hurts it a bit. But I think it's one of the best speed-vs-elegance tradeoffs.
musicfreak
+7  A: 

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);
        }
    }
}
Juliet
That's what boost::variant is for :-)
Zifre
That is quite a difference haha
Carson Myers
This is more of a consequence of a robust type system, I think, than specific to functional programming. On the other hand, there aren't too many really good type systems outside of functional programming environments, nor many functional programming environments without carefully considered type systems. -- Java in particular is a lousy example, whereby the designers started with an existing model, (C++) and removed the things they didn't like, instead of designing the type system to be expressive and *readable*!
TokenMacGuy
+4  A: 

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.

Methos
Common Lisp is not a strictly functional language, although it's easy to write functional programs in it. I don't know what sort of Lisp programming went into Viaweb.
David Thornley
I suppose that point is debatable, although, it wasn't said that FP *cannot* be used for web applications. Only that another paradigm is better suited to handle that task--I have never developed a web application myself, so I can't really debate it, but really what I'm looking for is situations where FP is the *right* (or wrong) choice and offers significant advantagers over imperative programming. Would you say web applications is one of those situations?
Carson Myers
Even I have not developed a web application. However Paul Graham certainly claims that using Lisp in that application was a major advantage. You can take a look at his essay here http://www.paulgraham.com/avg.html
Methos
That's because the alternative he was looking at was C Web apps. If his competitors had been using the Ruby and Python environments of today, I think he would have seen less of an advantage to Lisp.
Chuck
+4  A: 

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#
Hao Wooi Lim
That's a nice simple way of looking at it--Functional Programming is like a high level, but back end implementation. Thanks
Carson Myers
I almost give you a +1 until I notice VB is listed in there. No, I don't think you are wrong but I just hate VB that much.
Rosdi
I'll give you a +1 for Rosdi. Nice table.
Tim Perry
+1  A: 

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).

bortzmeyer
+2  A: 

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.