我已经阅读了维基百科上关于过程式编程和函数式编程的文章,但我还是有点困惑。有人能把它归结为核心吗?
当前回答
我在这里没有看到真正强调的一点是,现代函数语言(如Haskell)实际上更多地关注流控制的第一类函数,而不是显式递归。您不需要像上面那样在Haskell中递归地定义阶乘。我想是这样的
fac n = foldr (*) 1 [1..n]
是一个完美的惯用结构,在精神上更接近于使用循环,而不是使用显式递归。
其他回答
如果你有机会,我建议你买一份Lisp/Scheme,然后用它来做一些项目。最近流行起来的大多数思想都是在几十年前用Lisp表达的:函数式编程、延续(作为闭包)、垃圾收集,甚至XML。
所以这将是一个很好的方法来开始所有这些当前的想法,以及一些其他的,比如符号计算。
您应该知道函数式编程擅长什么,不擅长什么。它并不是什么都好。有些问题最好用副作用来表达,同样的问题会根据提问的时间给出不同的答案。
康拉德说:
因此,纯函数式程序总是为输入产生相同的值, 评价的顺序也不明确;这意味着不确定的值,比如 用户输入或随机值很难用纯函数式语言建模。
在一个纯函数式程序中求值的顺序可能很难(或者)解释(尤其是懒惰的人),甚至不重要,但我认为说它没有被很好地定义,听起来就像你根本无法判断你的程序是否会工作!
Perhaps a better explanation would be that control flow in functional programs is based on when the value of a function's arguments are needed. The Good Thing about this that in well written programs, state becomes explicit: each function lists its inputs as parameters instead of arbitrarily munging global state. So on some level, it is easier to reason about order of evaluation with respect to one function at a time. Each function can ignore the rest of the universe and focus on what it needs to do. When combined, functions are guaranteed to work the same[1] as they would in isolation.
... 像用户输入或随机值这样的不确定值很难纯粹地建模 函数式语言。
The solution to the input problem in purely functional programs is to embed an imperative language as a DSL using a sufficiently powerful abstraction. In imperative (or non-pure functional) languages this is not needed because you can "cheat" and pass state implicitly and order of evaluation is explicit (whether you like it or not). Because of this "cheating" and forced evaluation of all parameters to every function, in imperative languages 1) you lose the ability to create your own control flow mechanisms (without macros), 2) code isn't inherently thread safe and/or parallelizable by default, 3) and implementing something like undo (time travel) takes careful work (imperative programmer must store a recipe for getting the old value(s) back!), whereas pure functional programming buys you all these things—and a few more I may have forgotten—"for free".
我希望这听起来不像狂热,我只是想补充一些观点。命令式编程,特别是像c# 3.0这样的强大语言中的混合范式编程,仍然是完成工作的完全有效的方法,并且没有银弹。
[1]…除了内存使用方面(参考Haskell中的foldl和foldl')。
进一步阐述康拉德的评论:
因此,纯函数式程序总是对输入产生相同的值,求值的顺序没有很好的定义;
因此,函数式代码通常更容易并行化。由于函数(通常)没有副作用,并且它们(通常)只是作用于它们的参数,因此许多并发问题都消失了。
当您需要能够证明您的代码是正确的时,也可以使用函数式编程。这在过程式编程中要困难得多(在函数式编程中不容易,但仍然容易)。
免责声明:我已经很多年没有使用函数式编程了,直到最近才开始重新研究它,所以我在这里可能不完全正确。:)
过程式编程将语句序列和条件构造划分为单独的块,称为过程,这些块通过参数化(非函数式)值。
函数式编程与此类似,只是函数是一类值,因此它们可以作为参数传递给其他函数,并作为函数调用的结果返回。
注意,在这个解释中,函数式编程是过程式编程的泛化。然而,少数人将“函数式编程”解释为没有副作用,这与除Haskell之外的所有主要函数式语言都完全不同,但无关紧要。
要理解其中的区别,需要理解过程式编程和函数式编程的“教父”范式都是命令式编程。
基本上,过程式编程只是构造命令式程序的一种方式,其中主要的抽象方法是“过程”。(或某些编程语言中的“函数”)。甚至面向对象编程也只是构造命令式程序的另一种方式,其中状态被封装在对象中,成为一个具有“当前状态”的对象,加上这个对象有一组函数、方法和其他东西,可以让程序员操作或更新状态。
现在,关于函数式编程,其方法的要点是它确定要取什么值,以及应该如何传递这些值。(因此没有状态,也没有可变数据,因为它将函数作为第一类值,并将它们作为参数传递给其他函数)。
PS:理解所使用的每一种编程范式应该能澄清它们之间的差异。
PSS:归根结底,编程范式只是解决问题的不同方法。
PSS: quora上的这个答案有一个很好的解释。