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


当前回答

Funtional编程

num = 1 
def function_to_add_one(num):
    num += 1
    return num


function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)

#Final Output: 2

过程式编程

num = 1 
def procedure_to_add_one():
    global num
    num += 1
    return num


procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()

#Final Output: 6

Function_to_add_one是一个函数

Procedure_to_add_one是一个过程

即使你运行这个函数5次,每次它都会返回2

如果你运行这个过程五次,在第五次运行结束时,它会给你6。

免责声明:显然,这是对现实的一种超简化的看法。这个答案只是让我们了解了“函数”而不是“过程”。仅此而已。一旦你尝到了这种肤浅而深刻的直觉,开始探索这两种范式,你就会开始清楚地看到它们的区别。

对我的学生有帮助,希望对你们也有帮助。

其他回答

这里没有一个答案显示了惯用的函数式编程。递归阶乘的答案很适合在FP中表示递归,但大多数代码不是递归的,所以我不认为这个答案是完全具有代表性的。

假设你有一个字符串数组,每个字符串表示一个整数,比如“5”或“-200”。您希望根据内部测试用例检查这个输入字符串数组(使用整数比较)。两种解决方案如下所示

程序上的

arr_equal(a : [Int], b : [Str]) -> Bool {
    if(a.len != b.len) {
        return false;
    }

    bool ret = true;
    for( int i = 0; i < a.len /* Optimized with && ret*/; i++ ) {
        int a_int = a[i];
        int b_int = parseInt(b[i]);
        ret &= a_int == b_int;  
    }
    return ret;
}

功能

eq = i, j => i == j # This is usually a built-in
toInt = i => parseInt(i) # Of course, parseInt === toInt here, but this is for visualization

arr_equal(a : [Int], b : [Str]) -> Bool =
    zip(a, b.map(toInt)) # Combines into [Int, Int]
   .map(eq)
   .reduce(true, (i, j) => i && j) # Start with true, and continuously && it with each value

虽然纯函数式语言通常是研究语言(因为现实世界喜欢免费的副作用),但现实世界的过程式语言在适当的时候会使用更简单的函数式语法。

这通常是用Lodash这样的外部库实现的,或者是用Rust这样的新语言内置的。函数式编程的繁重工作是通过map、filter、reduce、currying、partial等函数/概念完成的,最后三个你可以查阅以进一步理解。

齿顶高

In order to be used in the wild, the compiler will normally have to work out how to convert the functional version into the procedural version internally, as function call overhead is too high. Recursive cases such as the factorial shown will use tricks such as tail call to remove O(n) memory usage. The fact that there are no side effects allows functional compilers to implement the && ret optimization even when the .reduce is done last. Using Lodash in JS, obviously does not allow for any optimization, so it is a hit to performance (Which isn't usually a concern with web development). Languages like Rust will optimize internally (And have functions such as try_fold to assist && ret optimization).

我从来没有在其他地方看到过这样的定义,但我认为这很好地总结了这里给出的差异:

函数式编程主要关注表达式

过程式编程主要关注语句

表达式有值。函数式程序是一个表达式,其值是由计算机执行的一系列指令。

语句没有值,而是修改一些概念机器的状态。

在纯函数式语言中,没有语句,也就是说没有办法操纵状态(它们可能仍然有一个名为“语句”的语法结构,但除非它操纵状态,否则我不会在这种意义上称其为语句)。在纯程序语言中,没有表达式,一切都是操纵机器状态的指令。

Haskell是纯函数式语言的一个例子,因为没有办法操纵状态。机器代码是纯过程语言的一个例子,因为程序中的所有内容都是操作机器寄存器和内存状态的语句。

令人困惑的部分是,绝大多数编程语言同时包含表达式和语句,允许您混合使用范式。语言可以根据它们鼓励使用语句和表达式的程度被分类为更函数化或更过程化。

For example, C would be more functional than COBOL because a function call is an expression, whereas calling a sub program in COBOL is a statement (that manipulates the state of shared variables and doesn't return a value). Python would be more functional than C because it allows you to express conditional logic as an expression using short circuit evaluation (test && path1 || path2 as opposed to if statements). Scheme would be more functional than Python because everything in scheme is an expression.

你仍然可以在一种鼓励过程范式的语言中以函数式风格编写,反之亦然。只是在语言不鼓励的范式下写作更困难和/或更尴尬。

在计算机科学中,函数式编程是一种编程范式,它将计算视为数学函数的求值,并避免状态和可变数据。它强调函数的应用,与强调状态变化的过程式编程风格相反。

我相信过程式/函数式/目标式编程是关于如何处理问题的。

The first style would plan everything in to steps, and solves the problem by implementing one step (a procedure) at a time. On the other hand, functional programming would emphasize the divide-and-conquer approach, where the problem is divided into sub-problem, then each sub-problem is solved (creating a function to solve that sub problem) and the results are combined to create the answer for the whole problem. Lastly, Objective programming would mimic the real world by create a mini-world inside the computer with many objects, each of which has a (somewhat) unique characteristics, and interacts with others. From those interactions the result would emerge.

每种编程风格都有自己的优点和缺点。因此,做一些诸如“纯编程”(即纯粹的程序设计——顺便说一下,没有人会这样做,这有点奇怪——或纯粹的函数式或纯粹的目标)是非常困难的,如果不是不可能的话,除了一些专门设计来展示编程风格优势的基本问题(因此,我们称那些喜欢纯粹的人为“weenie”:D)。

Then, from those styles, we have programming languages that is designed to optimized for some each style. For example, Assembly is all about procedural. Okay, most early languages are procedural, not only Asm, like C, Pascal, (and Fortran, I heard). Then, we have all famous Java in objective school (Actually, Java and C# is also in a class called "money-oriented," but that is subject for another discussion). Also objective is Smalltalk. In functional school, we would have "nearly functional" (some considered them to be impure) Lisp family and ML family and many "purely functional" Haskell, Erlang, etc. By the way, there are many general languages such as Perl, Python, Ruby.

@Creighton:

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

prouduct list = foldr 1 (*) list

或者仅仅是:

product = foldr 1 (*)

惯用语的阶乘

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

很简单

fac n = product [1..n]