Can someone explain to me why I would need functional programming instead of OOP?
Possible Duplicate:
Functional programming vs Object Oriented programming
有人能告诉我为什么我需要函数式编程而不是OOP吗?
为什么我需要使用Haskell而不是C++(或者类似的语言)?
与OOP相比,函数式编程的优势是什么?
one of the大事情可能在缺乏功能的"幽灵programming is the action at a的距离。"你是什么,你得到与EEA和不涵盖更多。这将使代码easier about to reason。P></
让我们用简单的实例。让我们说如何在Java代码片段中的无论哪种茶
在Java很复杂:黑莓P></
和Java语言面向对象的relatively是无知的。the number of that can be screwed
and the thing is?example of this is just a simple operation can be普通知识,让更多的OOP在安(或其他复杂的强制性)比在语言功能。EN address of the利益也不T功能编程,不交mutable,等.高阶函数的类。P></
哈斯克尔有三件事我觉得很酷:好的。
1)它是一种静态类型的语言,非常有表现力,允许您快速构建高度可维护和可重构的代码。在静态类型语言如Java和C语言以及Python和Ruby之类的动态语言之间一直存在着很大的争论。Python和Ruby使您可以快速构建程序,只使用Java或C语言所需的行数的一部分。因此,如果您的目标是快速进入市场,那么python和ruby是不错的选择。但是,因为它们是动态的,重构和维护代码是很困难的。在Java中,如果要向方法添加参数,则很容易使用IDE来查找方法的所有实例并修复它们。如果你错过了一个,编译器就会抓住它。使用python和ruby,重构错误只会被捕获为运行时错误。因此,对于传统语言,一方面可以在快速开发和糟糕的可维护性之间进行选择,另一方面可以在缓慢开发和良好的可维护性之间进行选择。两种选择都不是很好。好的。
但是有了哈斯克尔,你不必做出这种选择。Haskell是静态类型的,就像Java和C.*一样。因此,您可以获得所有的可重构性、潜在的IDE支持和编译时检查。但同时,编译器可以推断类型。所以,它们不会像处理传统静态语言那样妨碍您的工作。此外,该语言还提供了许多其他特性,使您只需几行代码就可以完成很多工作。因此,您可以得到Python和Ruby的开发速度以及静态语言的安全性。好的。
2)平行度。因为函数没有副作用,所以编译器可以更容易地并行运行,而不需要开发人员做太多的工作。考虑以下伪代码:好的。
1 2 3 | a = f x b = g y c = h a b |
在纯函数语言中,我们知道函数f和g没有副作用。所以,没有理由在g之前运行f。可以交换订单,或者同时运行它们。实际上,在函数h中需要f和g的值之前,我们根本不需要运行f和g。在传统语言中,这是不正确的,因为对f和g的调用可能会产生副作用,需要我们以特定的顺序运行它们。好的。
随着计算机上越来越多的内核,函数式编程变得越来越重要,因为它允许程序员轻松地利用可用的并行性。好的。
3)关于haskell的最后一件很酷的事情可能也是最微妙的:懒惰的评估。要理解这一点,可以考虑编写一个程序来读取文本文件并打印出文件每行中出现"the"一词的次数。假设您使用的是传统的命令式语言。好的。
尝试1:编写一个函数,打开文件并一次读取一行。对于每一行,计算"the"的数目,然后打印出来。这很好,除了您的主逻辑(计算单词)与您的输入和输出紧密耦合。假设您想在其他上下文中使用相同的逻辑?假设您想从一个套接字中读取文本数据并计算单词数?或者您想从用户界面读取文本?你必须重新改写你的逻辑!好的。
最糟糕的是,如果你想为你的新代码编写一个自动测试怎么办?您必须构建输入文件、运行代码、捕获输出,然后将输出与预期结果进行比较。这是可行的,但很痛苦。通常,当IO与逻辑紧密结合时,测试逻辑会变得非常困难。好的。
尝试2:那么,让我们分离IO和逻辑。首先,将整个文件读取到内存中的一个大字符串中。然后,将字符串传递给一个将字符串拆分为行的函数,计算每行的"s",并返回一个计数列表。最后,程序可以循环计数并输出它们。现在很容易测试核心逻辑,因为它不涉及IO。现在很容易将核心逻辑与来自文件、套接字或UI的数据一起使用。所以,这是一个很好的解决方案,对吧?好的。
错了。如果有人传入100GB文件怎么办?因为整个文件必须加载到一个字符串中,所以您将耗尽内存。好的。
尝试3:围绕读取文件和生成结果构建一个抽象。您可以将这些抽象看作两个接口。第一个方法有nextline()和done()。第二个具有outputCount()。您的主程序实现nextline()和done()从文件中读取,而outputcount()直接打印出计数。这允许主程序在恒定内存中运行。您的测试程序可以使用这个抽象的另一个实现,这个抽象有nextline()和done()从内存中提取测试数据,而outputcount()检查结果而不是输出结果。好的。
第三次尝试很好地分离了逻辑和IO,它允许程序在恒定内存中运行。但是,这比前两次尝试要复杂得多。好的。
简而言之,传统的命令式语言(无论是静态的还是动态的)常常让开发人员在好的。
a)IO与逻辑的紧密耦合(难以测试和重用)好的。
b)将所有内容加载到内存中(效率不高)好的。
c)构建抽象(复杂,并且会减慢实现速度)好的。
当读取文件、查询数据库、读取套接字等时,就会出现这些选择。程序员似乎更喜欢选项A,因此单元测试也会受到影响。好的。
那么,哈斯克尔对此有何帮助?在Haskell中,您可以像尝试2中一样解决这个问题。主程序将整个文件加载到一个字符串中。然后它调用一个函数来检查字符串并返回一个计数列表。然后主程序打印计数。测试和重用核心逻辑非常容易,因为它与IO隔离。好的。
但是内存使用情况呢?哈斯凯尔懒惰的评价会帮你解决这个问题。因此,即使您的代码看起来像是将整个文件内容加载到一个字符串变量中,但实际上并没有加载整个内容。相反,只在使用字符串时读取文件。这允许一次读取一个缓冲区,实际上您的程序将在恒定内存中运行。也就是说,您可以在100GB文件上运行这个程序,它将消耗很少的内存。好的。
类似地,您可以查询数据库,构建包含大量行的结果列表,并将其传递给函数进行处理。处理函数不知道行来自数据库。所以,它与IO是分离的。并且在封面下,行列表将被懒惰而有效地获取。所以,即使当您查看代码时看起来像这样,完整的行列表永远不会同时全部在内存中。好的。
最终结果是,您可以测试处理数据库行的函数,而不必连接到数据库。好的。
懒惰的评价真的很微妙,需要一段时间才能让你的头脑清醒过来。但是,它允许您编写易于测试和重用的简单代码。好的。
这里是最后的Haskell解决方案和方法3 Java解决方案。两者都使用恒定内存,并将IO与处理分离,以便测试和重用。好的。
Haskell:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | module Main where import System.Environment (getArgs) import Data.Char (toLower) main = do (fileName : _) <- getArgs fileContents <- readFile fileName mapM_ (putStrLn . show) $ getWordCounts fileContents getWordCounts = (map countThe) . lines . map toLower where countThe = length . filter (=="the") . words |
爪哇:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.Reader; class CountWords { public interface OutputHandler { void handle(int count) throws Exception; } static public void main(String[] args) throws Exception { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(new File(args[0]))); OutputHandler handler = new OutputHandler() { public void handle(int count) throws Exception { System.out.println(count); } }; countThe(reader, handler); } finally { if (reader != null) reader.close(); } } static public void countThe(BufferedReader reader, OutputHandler handler) throws Exception { String line; while ((line = reader.readLine()) != null) { int num = 0; for (String word: line.toLowerCase().split("([.,!?:;'"-]|\\s)+")) { if (word.equals("the")) { num += 1; } } handler.handle(num); } } } |
好啊。
如果我们出现Haskell语言和C + +的功能,使调试非常容易,因为没有被发现的类和变量mutable酮C、Python等。which should你永远亲爱的一切,和它ensured Arguments given some that,总是会返回,函数结果尽管the same the number of时报评价你的恩。P></
面向对象的编程范式是正交to any,which there are lanugages和FP与面向对象的组合,是最流行的ocaml implementations Haskell,several等。P></