【问题标题】:Is Fortran a purely functional language?Fortran 是纯函数式语言吗?
【发布时间】:2020-05-12 09:51:28
【问题描述】:

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

【问题讨论】:

  • “Fortran ... 是一种通用的编译命令式编程语言” en.wikipedia.org/wiki/Fortran(强调我的)
  • @kaya3 你能提供任何关于为什么 fortran 适合命令式范式的见解吗?这意味着fortran只描述了“如何”做某事,而不是“它试图做什么”?这是如何确定的?
  • @kaya3 fortran 可以同时作为命令式和声明式吗?
  • 有关信息,有一个项目实现了许多功能以在 Fortran 中启用函数式编程:github.com/wavebitscientific/functional-fortran 这不会改变 Fortran 的主要命令性质,但对这个主题很有趣 :-)

标签: functional-programming fortran programming-languages fortran90 paradigms


【解决方案1】:

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

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

数学函数

mathematical function 是输入和输出之间的映射:

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

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

这样的函数
def greeting(name):
    return 'Hello, ' + name

在 Python 中被认为是一个数学函数,而类似的函数

def print_square(x):
    print(x ** 2)
    return None

不被视为数学函数。请注意,计算本质上是否是数学计算与它是否是数学意义上的函数无关。 print_square 做了一些算术运算,这比greeting 做的更像数学。但是greeting 是一个数学函数,而print_square 不是。

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

'Alice'   → 'Hello, Alice'
'Bob'     → 'Hello, Bob'
'Charles' → 'Hello, Charles'
'####'    → 'Hello, ####'
''        → 'Hello, '
...

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

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

12 → None
4  → None
...

这些映射(从整数集到 {None} 集)没有正确定义 print_square 的作用,即它计算输入和 prints it to the console 的平方。

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

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

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

纯函数式编程

purely functional 编程语言是一种所有计算都由纯函数完成的语言:

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

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

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

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

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

命令式编程

Imperative programming 是:

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

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

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

“什么”与“如何”

“这意味着 fortran 只描述了‘如何’做某事而不是‘它试图做什么’?”

人们常说,命令式程序是说“如何”进行计算的程序,而声明式程序只说“应该做什么”。连维基百科says so

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

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

那么描述程序应该“如何”做某事或应该完成“什么”的 Fortran 代码也是如此吗?

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

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

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

【讨论】:

  • 非常感谢您将其布置成这样!它有很大帮助,现在更有意义了!!
  • @HeapOverflow 我不是数学家,但我的基本直觉是,如果您将function 定义为从集合X 到集合Y 的映射,那么print_square 不是函数因为它不提供这样的映射。
  • @HeapOverflow 是的,这就是我的意思。我已经进行了编辑以使其明确。
  • 嗯。不要说得太细,但实际上它确实定义了一个映射。它从一组数字映射到其中包含单个元素的集合(“无”)。没有要求我知道映射是双射的。它还会在此过程中产生副作用,使其不纯。无论如何,副作用是函数的目的。
  • @melston "这些映射(从整数集到 {None} 集)没有正确定义 print_square 的作用,即它计算输入的平方并打印它到控制台。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 2011-03-08
  • 2010-10-30
  • 2020-12-07
  • 2013-03-27
  • 1970-01-01
相关资源
最近更新 更多