Fortran 是一种纯函数式语言吗?

cod*_*y99 3 paradigms fortran programming-languages functional-programming fortran90

我知道有些语言在编程中结合了许多不同范式的元素。有人告诉我 Fortran 是函数式语言的一个例子,但是我对它是否是纯函数式有点困惑,因为它似乎主要用于数学函数,但是我也读到它是也可以将面向对象的编程应用于 Fortran,那么它是某种混合吗?

kay*_*ya3 8

“我对它是否是纯函数有点困惑,因为它似乎主要用于数学函数”

这似乎是对“纯函数”一词含义的误解,也可能是对“数学函数”一词含义的误解。

数学函数

数学函数是输入和输出之间的映射:

在数学中,函数是集合之间的关系,它与第一个集合的每个元素恰好关联到第二个集合的一个元素。

在编程语言的上下文中,函数的输入是它的参数,输出是它的返回值,例如像这样的函数

def greeting(name):
    return 'Hello, ' + name
Run Code Online (Sandbox Code Playgroud)

在 Python 中被认为是一个数学函数,而像这样的函数

def print_square(x):
    print(x ** 2)
    return None
Run Code Online (Sandbox Code Playgroud)

不被视为数学函数。这里要注意,计算是否是数学性质的与它是否数学意义上的函数无关;print_square做一些算术,这更像是数学而不是什么greeting。但greeting是一个数学函数,print_square而不是。

greeting是一个数学函数,因为它是从字符串集到字符串集的映射,并且该函数可以通过什么输入与什么输出相关联来描述。完整地写出映射需要无限多的行,但映射是这样的:

'Alice'   ? 'Hello, Alice'
'Bob'     ? 'Hello, Bob'
'Charles' ? 'Hello, Charles'
'####'    ? 'Hello, ####'
''        ? 'Hello, '
...
Run Code Online (Sandbox Code Playgroud)

第一个集合(即所有字符串的集合)中的每个元素都与第二个集合中的一个元素相关联,因此greeting满足数学函数的定义。

相比之下,print_square不是数学函数,因为它不能通过从输入到输出的映射来描述:

12 ? None
4  ? None
...
Run Code Online (Sandbox Code Playgroud)

这些映射(从整数集到集{None})没有正确定义什么print_square,即它计算输入的平方并将其打印到控制台

为了避免与“进行数学运算的函数”混淆,最好使用计算术语“纯函数”:

...纯函数是数学函数的计算模拟。

因此,为了解决您关于 Fortran “似乎主要用于数学函数”的评论,Fortran 主要用于进行数学计算,但这不是“数学函数”的意思。

纯函数式编程

一个纯粹的函数编程语言是一个所有的计算是由纯函数来完成:

在计算机科学中,纯函数式编程通常指定一种编程范式……将所有计算视为对数学函数的评估。纯函数式编程也可以通过禁止改变状态和可变数据来定义。

请注意,编程语言仅允许您编写纯函数是不够的;这个定义说所有的计算都必须由纯函数完成,这样语言才有资格成为纯函数。

Fortran 是一种纯函数式语言吗?不它不是。Fortran 中的子程序可以根据输入和输出之间的映射进行返回值以外的操作;Fortran 中的计算可以通过状态更改和可变数据来完成。一个例子就足够了:这个来自Rosetta Code

subroutine hs(number, length, seqArray)
  integer, intent(in)  :: number
  integer, intent(out) :: length  
  integer, optional, intent(inout) :: seqArray(:)
  integer :: n
 
  n = number
  length = 1
  if(present(seqArray)) seqArray(1) = n
  do while(n /= 1)
    if(mod(n,2) == 0) then
      n = n / 2
    else
      n = n * 3 + 1
    end if
    length = length + 1
    if(present(seqArray)) seqArray(length) = n
  end do
end subroutine
Run Code Online (Sandbox Code Playgroud)

变量n显然是可变的,因为它的状态在循环中改变。此外,数组seqArray是可变的,它既是子例程的输入也是输出,子例程会更改数组的状态。所以这个子程序没有定义纯函数,它使用了“变化状态和可变数据”,这是纯函数语言的定义所禁止的。

所以子程序hs没有定义“数学函数”,即使它执行的计算本质上是数学的。

命令式编程

命令式编程是:

... 一种使用语句改变程序状态的编程范式。...命令式程序由计算机执行的命令组成。

上面显示的 Fortran 子例程满足这两个定义:它使用语句或命令来更改计算机执行的程序状态。所以 Fortran 是一种命令式编程语言。

请注意,与维基百科对“纯函数式”的定义不同,一种语言即使不以这种方式进行所有计算,也可以是命令式的。因此,尽管可以在 Fortran 中编写不能通过更改程序状态来工作的纯函数,但 Fortran 是必不可少的;只是也许不是“绝对必要的”。

“什么”与“如何”

“这意味着 Fortran 只描述了'如何'做某事,而不是它试图做的'什么'?”

人们常说,命令式程序说明计算应该“如何”完成,而声明式程序只说明“应该做什么”。连维基百科都这么说

命令式编程侧重于描述程序如何运行。

该术语通常与声明式编程形成对比,声明式编程侧重于程序应该完成什么,而不指定程序应该如何实现结果。

那么 Fortran 代码是描述程序应该“如何”做某事,还是它应该完成“什么”?

语句 liken = n / 2是告诉计算机做某事的命令;在计算机执行命令之前有一个程序状态,之后有一个不同的程序状态。该语句n = n / 2还告诉计算机“如何”执行命令:将 的当前值n除以 2,并将结果存储在变量 中n。所以根据“如何”/“什么”的区别,Fortran 是命令式的,而不是声明式的。

但是你可能会争辩说:n = n / 2说出我们想要实现的“什么”;一个新的程序状态,其中n保留旧状态的值,除以 2。你是对的,它确实这么说,至少对阅读它的人来说是这样。

这表明“如何”/“什么”的区别太模糊,无法用作决定语言是命令式还是声明式的定义。它的意思是作为这些范式之间的松散描述的对比,而不是作为任一范式的定义。要确定一种语言是命令式的还是纯函数式的,或者在任何其他范式中,您应该参考该范式的有用定义。