我已经阅读了维基百科上关于过程式编程和函数式编程的文章,但我还是有点困惑。有人能把它归结为核心吗?


当前回答

进一步阐述康拉德的评论:

因此,纯函数式程序总是对输入产生相同的值,求值的顺序没有很好的定义;

因此,函数式代码通常更容易并行化。由于函数(通常)没有副作用,并且它们(通常)只是作用于它们的参数,因此许多并发问题都消失了。

当您需要能够证明您的代码是正确的时,也可以使用函数式编程。这在过程式编程中要困难得多(在函数式编程中不容易,但仍然容易)。

免责声明:我已经很多年没有使用函数式编程了,直到最近才开始重新研究它,所以我在这里可能不完全正确。:)

其他回答

过程式编程将语句序列和条件构造划分为单独的块,称为过程,这些块通过参数化(非函数式)值。

函数式编程与此类似,只是函数是一类值,因此它们可以作为参数传递给其他函数,并作为函数调用的结果返回。

注意,在这个解释中,函数式编程是过程式编程的泛化。然而,少数人将“函数式编程”解释为没有副作用,这与除Haskell之外的所有主要函数式语言都完全不同,但无关紧要。

@Creighton:

在Haskell中有一个叫做product的库函数:

prouduct list = foldr 1 (*) list

或者仅仅是:

product = foldr 1 (*)

惯用语的阶乘

fac n = foldr 1 (*)  [1..n]

很简单

fac n = product [1..n]

进一步阐述康拉德的评论:

求值的顺序不是 定义良好的

一些函数式语言有所谓的惰性求值。这意味着直到需要该值时才执行函数。在此之前,传递的是函数本身。

过程式语言是步骤1、步骤2、步骤3……如果在第二步你说加2 + 2,它马上就会做。在惰性求值中,你会说2 + 2,但如果结果从未被使用,它就永远不会做加法。

函数式语言(理想情况下)允许您编写一个数学函数,即接受n个参数并返回一个值的函数。如果程序被执行,这个函数将根据需要在逻辑上求值

另一方面,过程式语言执行一系列连续的步骤。(有一种将顺序逻辑转换为函数逻辑的方法,称为连续传递样式。)

因此,纯函数式程序总是对输入产生相同的值,求值的顺序没有很好的定义;这意味着像用户输入或随机值这样的不确定值很难用纯函数式语言建模。


就像这个答案中的其他内容一样,这是一种概括。这个属性,在需要计算结果的时候计算,而不是在调用它的时候按顺序计算,被称为“懒惰”。并不是所有的函数式语言都是懒惰的,懒惰也不仅仅局限于函数式编程。相反,这里给出的描述提供了一个“心理框架”,用于思考不同的编程风格,这些风格不是不同的、相反的类别,而是流动的想法。

康拉德说:

因此,纯函数式程序总是为输入产生相同的值, 评价的顺序也不明确;这意味着不确定的值,比如 用户输入或随机值很难用纯函数式语言建模。

在一个纯函数式程序中求值的顺序可能很难(或者)解释(尤其是懒惰的人),甚至不重要,但我认为说它没有被很好地定义,听起来就像你根本无法判断你的程序是否会工作!

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')。