haskell-函数式编程能最好/最坏地解决哪些问题?

我经常听到函数式编程解决了许多在过程式/命令式编程中很难解决的问题。 但是我也听说过,过程编程自然很擅长解决其他一些问题。

在我开始阅读有关Haskell的书并深入研究函数式编程之前,我至少想要一个基本的概念,以了解我可以真正将其用于什么(书中的示例之外)。 那么,函数式编程最擅长哪些方面? 它不太适合哪些问题?

更新资料

到目前为止,我对此有一些很好的答案。 我迫不及待想现在开始学习Haskell-我只需要等待直到我掌握C :)

函数式编程之所以如此出色的原因:

  • 非常简洁明了-它可以用简短,清晰的陈述表达复杂的想法。
  • 比命令性语言更容易验证-在系统安全至关重要的情况下很好。
  • 功能的纯正和数据的不变性使并发编程更加合理。
  • 非常适合编写脚本和编写编译器(不过我很想知道为什么)。
  • 与数学相关的问题可以简单而精美地解决。

函数式编程遇到的问题:

  • 值得商:的:Web应用程序(尽管我想这取决于应用程序)。
  • 桌面应用程序(尽管它可能取决于语言,但是F#会很好,不是吗?)。
  • 性能至关重要的任何事物,例如游戏引擎。
  • 任何涉及大量程序状态的事物。
Carson Myers asked 2020-08-12T00:51:59Z
11个解决方案
13 votes

由于存在更高级别的函数(map,lfold,grep)和类型推断,因此函数式编程在简洁性方面表现出色。

出于相同的原因,它在通用编程方面也很出色,并且进一步提高了在简短的陈述中表达复杂思想而不会引起混淆的能力。

我欣赏这些属性,因为它们使交互式编程变得合理。 (例如R,SML)。

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

Alex Brown answered 2020-08-12T00:52:19Z
11 votes

我会说函数式编程适合解决问题,例如 AI问题,数学问题(这太容易了),游戏引擎,但不太适合GUI和自定义控件开发或需要精美UI的桌面应用程序。 我认为以下方法很直观(尽管可能过于笼统):

            Back-end   Front-end
Low-level   C          C++
High-level  FP         VB, C#
Hao Wooi Lim answered 2020-08-12T00:52:40Z
6 votes

函数式编程对于并行编程将是有益的。 您不依赖于功能编程的状态变化这一事实意味着各种处理器/内核不会互相影响。 因此,非常适合并行性的算法类型,例如压缩,图形效果和一些复杂的数学任务,通常也很适合用于函数式编程。 而且,多核CPU和GPU仅在普及中这一事实也意味着对此类事物的需求将会增长。

Steve Wortham answered 2020-08-12T00:53:01Z
6 votes

它可能不直接与函数式编程联系在一起,但是在数据结构的设计和实现中没有比这更好的了。 让我们比较两个等效的代码段:

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 answered 2020-08-12T00:53:30Z
4 votes

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

  • 并发
  • 编译器
  • 脚本编写

我个人发现的问题不太适合:

  • Web应用程序(但这可能只是我自己,例如《黑客新闻》是在LISP中实现的)
  • 桌面应用
  • 游戏引擎
  • 你绕过很多州的事情
boxofrats answered 2020-08-12T00:54:25Z
4 votes

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

就性能而言,最不适合的是它。 您对所使用的算法的控制较少,因为它比声明式更具声明性。

Jacob answered 2020-08-12T00:54:50Z
4 votes

我不同意FP不能用于Web应用程序。 我知道Paul Grahm和Robert Morris创立了Viaweb,该公司使用Lisp交付Web应用程序。 我认为随着您越来越接近硬件(设备驱动程序,内核等),人们希望使用尽可能低级的语言。 这是因为如果使用了更多的抽象,则在发生错误的情况下更难以调试。 看看Joel Spolsky的文章“泄漏抽象法则”。

Methos answered 2020-08-12T00:55:11Z
3 votes

实际上,我喜欢将纯函数代码用于需要管理大量状态的问题。 这些种类的语言倾向于为状态的显式处理提供最佳的机制,因为它们不允许您隐式地进行处理。 在小规模上隐式管理状态似乎更容易,但是一旦状态开始变得复杂,您就会遇到麻烦,而没有正确性保证您只能以FP方式进行操作。

answered 2020-08-12T00:55:32Z
2 votes

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

mduvall answered 2020-08-12T00:55:52Z
2 votes

我要说的是,函数式编程将对低级内容,操作系统内核,设备驱动程序等产生麻烦。

我说的是“有麻烦”,而不是“不能使用”(由于图灵的等效性,任何东西都可以用于任何东西)。

一个有趣的问题是,此问题对于功能性编程是否至关重要(因为物理设备具有状态),还是我们可以想象面向系统的功能性编程语言/环境。 例如,BitC仅部分起作用(它在很大程度上依赖于可变性)。

bortzmeyer answered 2020-08-12T00:56:21Z
1 votes

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

KIMA answered 2020-08-12T00:56:42Z
translate from https://stackoverflow.com:/questions/998552/what-are-some-problems-best-worst-addressed-by-functional-programming