程序语言和函数语言之间的区别?

时间:2015-05-17 04:27:47

标签: c haskell functional-programming procedural

我最近在一次采访中被问到了这个问题。我无法得到正确的答案。

当您以过程语言(如C)和具有相同参数的函数语言(如haskell)重复调用函数时,您可能会得到不同的结果?我在[this](What is the difference between procedural programming and functional programming?)帖子上读到,纯函数式语言总会产生相同的答案。对于函数式语言而言,为什么这样呢?而不是程序语言呢?

3 个答案:

答案 0 :(得分:3)

纯函数式语言的操作使得相同的输入总是产生相同的输出,纯函数没有副作用。但是,在程序性或非纯函数式语言(如C)中,可能会出现副作用,例如指针被修改,或其他外部因素,如时间或文件I / O.甚至Haskell也可以进行文件I / O.因此,如果带有I / O的Haskell是纯函数式语言,那么C and the cpp are purely functional, too

以此C程序为例:

#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif

#include <stdio.h>
#include <time.h>
#include <unistd.h>

int get_num(int n)
{
    usleep(1100000);
    return (time(NULL) - n) % (n / 10);
}

int main(void)
{
    int i;

    for (i = 0; i < 10; i++)
        printf("%d\n", get_num(4242));

    return 0;
}

我们将输入的常量参数4242设为get_num。在任意数学运算之后,由于时间因素和休眠,相同的输入在这种过程语言中不会产生相同的输出。

一次运行,我们得到:

247
248
249
250
251
253
254
255
256
257

稍后运行,我们得到:

270
271
272
273
274
275
277
278
279
280

在大多数C中,副作用比比皆是。但是,在纯粹的功能性语言中,这种副作用将不存在或不可能。

答案 1 :(得分:3)

在命令式编程中,允许函数产生副作用,例如修改变量值,写入文件,访问网络等。第二次运行相同的函数时,它可以检测以前的副作用并返回不同的东西。一个简单的C示例是:

int i = 0;
int foo() {
  return i++;
}

多次调用会产生不同的数字。另一个例子:

int foo(int *p) {
  return (*p)++;
}

即使用相同的参数调用上面的参数,即相同的指针,由于增量,结果也会不同。

函数式编程中,设计禁止使用i++等副作用。这样,函数的输出必须仅依赖于其参数的值。例如。如果在Haskell中我们有一个类型为f的函数Int -> Int,我们可以确保f 3在每次调用时都会返回相同的整数。

嗯,以上并不完全正确 - 程序最终必须做一些I / O,否则就没有意义了。因此,必须以某种形式提供副作用。在Haskell中,实际上允许带副作用的函数,但它们的类型必须告诉它们不是纯函数。例如。如果函数g具有类型Int -> IO Int,那么它可以执行I / O并产生副作用:运行print =<< g 3每次都可以打印不同的值,就像在命令式编程中一样。

总而言之,在具有副作用的纯函数式编程函数中,与不具有副作用的函数具有不同的类型。通常,在精心设计的功能程序中,很少需要I / O和副作用,纯函数构成了绝大多数代码。因此,有时我们会说“纯函数式编程禁止副作用”,因为大多数代码都是在这种约束条件下编写的。

答案 2 :(得分:1)

为了进一步澄清,它不是一种语言的属性。没有命令式语言强迫您只编写副作用程序。尽管没有明确支持,但完全可以用纯函数样式编写。

函数式语言中,没有语言结构允许您修改变量,访问全局可见存储等。因此,有点夸张地说纯FP语言“禁止“不纯的功能 - 相反,首先没有办法写一个。请注意,即使是以下功能:

printTwice x = do {putStrLn x; putStrLn x}

不纯。 printTwice的应用导致IO操作。你可以多次这样做,把结果放在列表或元组中并传递它们,这都是纯粹的。具体来说,之间没有区别:

 twoActions = (printTwice "hello", printTwice "hello")

 twoActions = (a,a) where a = printTwice "hello"