什么是function编程最好/最差的问题?
我经常听说函数式编程解决了很多程序/命令式编程困难的问题。 但是我也听说过程序编程自然很擅长的其他问题并不是很好。
在我打开我关于Haskell的书,并深入到函数式编程之前,我至less想了解一下我可以真正使用它的基本概念(本书的例子之外)。 那么,函数式编程擅长什么呢? 有什么问题不适合?
更新
到目前为止,我已经得到了一些很好的答案。 我迫不及待地想要开始学习Haskell – 我只能等到掌握了C 🙂
函数式编程的原因很多:
- 非常简明扼要 – 它可以用简短而不混淆的陈述来expression复杂的想法。
- 比命令式语言更容易validation – 在系统安全性至关重要的情况下是很好的。
- 函数的纯度和数据的不变性使得并发编程更加合理。
- 非常适合脚本和编写编译器(我希望知道为什么)。
- math相关的问题简单而美观地解决。
函数式编程斗争的领域:
- Debatable :Web应用程序(尽pipe我猜这取决于应用程序)。
- 桌面应用程序(尽pipe它可能取决于语言,F#会好的这不是吗?)。
- 性能至关重要的任何东西,比如游戏引擎。
- 任何涉及大量程序状态的东西。
函数式编程由于存在更高层次的函数 (map,lfold,grep)和types推断 ,因此在简洁性方面更胜一筹。
generics编程也非常出色,出于同样的原因,进一步提高了在简短语句中expression复杂想法的能力,而不会造成混淆。
我感谢这些属性,因为它们使交互式编程看起来似乎合理。 (如R , SML )。
我怀疑function编程也可以更容易地validation其他编程方法,这在安全关键系统(核电站和医疗设备)中是有利的。
我会说function性编程适合解决问题,例如AI问题,math问题(这太容易了),游戏引擎,但不太适合GUI和自定义控件开发或需要花哨UI的桌面应用程序。 我觉得直觉思维以下的方式(虽然它可能是泛化太多):
Back-end Front-end Low-level C C++ High-level FP VB, C#
它可能并不直接与函数式编程联系在一起,但是在数据结构的devise和实现中并没有什么可以打动工会。 我们来比较两个等效的代码段:
F#:
键入'a stack =缺省值'a * stack | 零 让rec to_seq =函数 | 无 - > Seq.empty; | Cons(hd,tl) - > seq {yield hd; 产量! to_seq tl} 让rec追加xy = 与x匹配 | 无 - > y | 缺点(hd,tl) - >缺点(hd,append tl y) 让x = Cons(1,Cons(2,Cons(3,Cons(4,Nil)))) 让y = Cons(5,Cons(6,Cons(7,Cons(8,Nil)))) 让z =追加xy 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); } } }
函数式编程对于并行编程是很好的。 事实上你不依赖于函数编程的状态改变意味着各种处理器/内核不会互相促进。 因此,像压缩,graphics效果和一些复杂的math任务那样的并行性的algorithmtypes通常也是函数式编程的好select。 而多核CPU和GPU只是越来越stream行的事实也意味着对这种事物的需求将会增长。
我发现一些function编程的问题适合于:
- 并发
- 编译器
- 脚本
我个人觉得不太适合的问题:
- Web应用程序(但这可能只是我,黑客新闻,例如在LISP中实现)
- 桌面应用
- 游戏引擎
- 你经过很多州的东西
我发现Haskell非常适合做math相关的任何事情。 不是说这是一个真正的专业项目,而是我用它制作了一个数独解算器和扑克分析器。 有一个mathcertificate的程序是很好的。
至于它不适合什么是性能是一个优先事项。 您对所使用的algorithm的控制较less,因为它比命令更具说明性。
我不同意FP不能用于Web应用程序。 我知道Paul Grahm和Robert Morris开始使用Lisp来提供Web应用程序的Viaweb。 我认为,当你靠近硬件(设备驱动程序,内核等)时,我们希望尽可能使用低级语言。 这是因为如果使用更多的抽象,那么在错误的情况下更难debugging。 看看Joel Spolsky撰写的文章“漏洞抽象法”(The Law of Leaky Abstraction)。
其实,我喜欢用纯粹的function代码来处理需要pipe理很多状态的问题。 那些有点语言倾向于为显式处理状态提供最好的机制,因为它们不允许你隐式地处理。 隐式pipe理状态在小规模上似乎更容易,但是一旦状态开始变得复杂,在没有正确性的情况下就会遇到麻烦,从而保证了FP方式的执行。
我发现matrixmath的math问题函数式编程的简单性非常好,看看这些types的问题在Scheme中是如何解决的!
我会说function性编程对于低级别的东西,操作系统内核,设备驱动程序等都会有麻烦。
我说“有麻烦”,不是“不能使用”(因为图灵等价,任何东西都可以用于任何事情)。
一个有趣的问题是这个问题是否在函数式编程中是基础的(因为物理设备具有状态),或者我们可以想象面向系统的函数式编程语言/环境。 例如, BitC只是部分function(它依赖于很多可变性)。
function和面向对象的范式具有正交的强度。 你可以说函数式编程强调动词和面向对象的名词编程。 或者更实际一点:面向对象使得添加新数据变得简单,而function性编程则使添加新工具变得简单。 两者都需要修改代码来实现另一个目标。 您想阅读http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.18.4525&rep=rep1&type=pdf (合成面向对象和functiondevise以促进重用