功能编程最好/最差的问题是什么?

时间:2009-06-15 21:43:06

标签: haskell functional-programming

我经常听说函数式编程解决了许多在程序/命令式编程中难以解决的问题。但我也听说过程序编程在其他一些问题上并不是很好。

在我打开关于Haskell的书并深入研究函数式编程之前,我至少想了解一下我能用它的基本概念(在本书的例子之外)。那么,函数式编程擅长的是什么呢?它不适合的问题是什么?

更新

到目前为止,我已经得到了一些很好的答案。我迫不及待地开始学习Haskell - 我只需要等到我掌握C:)

函数式编程很棒的原因:

  • 非常简洁和简洁 - 它可以用简短的,未经过混淆的陈述表达复杂的想法。
  • 比命令式语言更容易验证 - 在系统安全至关重要的地方很好。
  • 函数的纯度和数据的不变性使得并发编程更加合理。
  • 非常适合脚本编写和编写程序(我很高兴知道为什么)。
  • 数学相关问题简单而精美地解决了。

功能性编程困难的领域:

  • Debatable :网络应用程序(虽然我猜这取决于应用程序)。
  • 桌面应用程序(虽然它可能取决于语言,F#会擅长这个不是吗?)。
  • 表现至关重要的任何事情,例如游戏引擎。
  • 任何涉及大量程序状态的事情。

11 个答案:

答案 0 :(得分:13)

由于存在higher level functions(map,lfold,grep)和type inference,函数式编程擅长简洁。

出于同样的原因,它在generic programming也很出色,并且进一步提高了在简短陈述中表达复杂想法的能力,而没有混淆。

我很欣赏这些属性,因为它们使interactive programming合理。 (例如RSML)。

我怀疑其他编程方法也可以更容易地验证功能编程,这在安全关键系统(核电站和医疗设备)中是有利的。

答案 1 :(得分:11)

我想说功能编程适合解决问题,例如AI问题,数学问题(这太容易了),游戏引擎但不太适合GUI和自定义控件开发或需要花哨UI的桌面应用程序。我发现通过以下方式思考是直观的(虽然它可能过于泛化):

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

答案 2 :(得分:6)

函数式编程对并行编程很有用。事实上,您不依赖于函数式编程的状态更改意味着各种处理器/内核不会互相踩踏。因此,对压缩,图形效果和一些复杂数学任务等并行性很好的算法类型通常也是函数式编程的良好候选者。事实上,多核CPU和GPU的普及程度也越来越高,这也意味着对这类产品的需求将会增长。

答案 3 :(得分:6)

它可能与函数式编程没有直接联系,但在数据结构的设计和实现中没有任何东西胜过联盟。让我们比较两个等价的代码:

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)

爪哇:

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 :(得分:4)

我发现函数式编程适合的一些问题:

  • 并发
  • 编译器
  • 脚本

我个人认为不太适合的问题:

  • 网络应用程序(但可能只是我,黑客新闻,例如在LISP中实施)
  • 桌面应用程序
  • 游戏引擎
  • 你传递许多州的事情

答案 5 :(得分:4)

我发现Haskell非常适合做任何与数学有关的事情。这不是一个真正的专业项目,但我用它做了一个数独求解器和扑克分析器。拥有一个在数学上可证明的程序很棒。

对于不太适合的东西,性能是优先考虑的事情。您对所使用的算法的控制较少,因为它更具说明性而不是命令式。

答案 6 :(得分:4)

我不同意FP不能用于Web应用程序。我知道Paul Grahm和Robert Morris创建了使用Lisp来提供Web应用程序的Viaweb。我认为随着您更接近硬件(设备驱动程序,内核等),人们希望尽可能使用低级语言。这是因为如果使用更多的抽象,则在出现错误时更难调试。看看Joel Spolsky的文章“漏洞抽象法”。

答案 7 :(得分:3)

实际上,我喜欢使用纯功能代码来解决需要管理大量状态的问题。这些语言倾向于为显式处理状态提供最好的机制,因为它们不允许你隐式地执行它。在小规模上隐式管理状态可能看起来更容易,但是一旦状态开始变得复杂,你就会遇到麻烦而没有正确性保证你从FP方式做到这一点。

答案 8 :(得分:2)

我发现矩阵数学的数学问题的函数式编程的简单性非常漂亮,看看如何在Scheme中解决这些类型的问题!

答案 9 :(得分:2)

我会说功能编程会对低级内容,操作系统内核,设备驱动程序等造成麻烦。

我说“有麻烦”,而不是“不能用”(因为图灵等价,任何东西都可以用于任何东西)。

一个有趣的问题是这个问题是否是函数式编程的基础(因为物理设备具有状态),或者我们是否可以想象面向系统的函数式编程语言/环境。例如,BitC只是部分功能(它很大程度上依赖于可变性)。

答案 10 :(得分:1)

功能和面向对象的范式具有正交强度。 你可以说函数式编程强调动词和面向对象的名词编程。 或者,更实际的说法: 面向对象使得添加新数据变得简单,而功能编程使添加新工具变得简单。 两者都需要更改代码才能实现其他目标。 您想阅读http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.18.4525&rep=rep1&type=pdf(合成面向对象和功能设计以促进重用