数学中的函数和编程中的函数有什么区别?
uemypmqf1#
在函数式编程中,我们有Referential Transparency,这意味着可以用函数的值替换函数,而不需要修改程序。* 这在数学中也是正确的*,但在命令式语言中并不总是正确的*。
主要的区别在于,如果你在数学中调用f(x),你总是得到相同的答案,但是如果你在C中调用f'(x),答案可能不一样--相同的参数并不总是返回相同的输出。而且取决于程序中的其他东西(封闭作用域、全局变量、内置函数、状态(如果使用面向对象))。math函数和C函数的另一个区别是,在Math中,您不能创建从非空集到空集的函数(在C中,这将是:你不需要总是返回一些东西),而且,不是所有的函数都是computable(我不知道在数学中是否有类似的东西),你没有无限集的函数(你有有限的内存,所以可能的输入参数集必须是有限的),但是在数学中,你可以定义一个无限集的函数(比如f:N -〉N)和uncountable集合(如f:R -〉R)(在C中你有浮点数,但它们只表示真实的的简化集,这是有限的)。
f(x)
f'(x)
总结:
在C语言中,您并不总是具有引用透明度。您的函数可能并不总是为相同的输入参数给予相同的输出。您可以拥有为无限输入集定义的数学函数,但在C语言函数中,您的输入是有限的。在C语言函数中,您可以拥有不返回任何值的函数,但在数学中,您不能拥有这种函数(如果你有一个有非空输入集的函数,你必须将每个元素Map到另一个集合中的一个)。
thigvfpy2#
这取决于领域(我不是指功能的领域,我是指学习的领域),也可能取决于语言。在数学中,对于给定的输入值,一个函数的输入只能Map到一个输出(请记住,垂直线测试);在编程中,这可能并不完全相同,这取决于你在“输入”和“函数逻辑”之间画的线。例如,假设我们有一个函数兰德(),它读取大气条件以得到一个真正的随机数,再假设一个调用函数将一个整型参数作为排序的乘数,那么下面这个函数是函数吗?
int giveRandAtmosWithMul(int mult) { return mult * rand(); }
从数学意义上讲,如果您将mult视为问题的唯一输入,那么它可能不是一个函数,但显然兰德()也提供了输入(尽管rand()在机器代码中总是具有相同的入口点)。正如您所看到的,如果没有一些大家都同意的标准协议,这些差异实际上是无法客观定义的。
mw3dktmi3#
我认为最重要的区别是数学(和函数式编程)中的函数不能改变状态,而(命令式)编程函数可以。
omhiaaxx4#
其他答案都是正确的--这是两件不同的事情,相反,我将证明它们是相关的,我将用->表示编程函数,用=>表示数学函数。假设你有一种支持异常的语言。在这种情况下,你可以把一个编程函数A -> B想象成一个数学函数A => B + E,其中“B + E”表示B类型的东西,或者E类型的东西。你的语言有两个从函数返回的关键字,“return”和“throw”。现在,您可以通过编写g(f(x))来组合两个函数f: A -> B和g: B -> C。这是一个接受A并返回C的函数。您可以在许多语言(如Java或Python)中执行此操作。实际上,如果f(x)抛出异常,g不会被调用,异常会被传播--想想g(1/0),语言会处理这个问题,你不需要检查f的结果是否是一个异常。数学上的描述方式是,虽然f: A => B+E和g: B => C+E,但语言将函数g“提升”为B+E => C+E。g现在是一个可能发生异常的函数,但它只会传播异常。换句话说,定义g': B+E => C+E为
->
=>
A -> B
A => B + E
B
E
g(f(x))
f: A -> B
g: B -> C
g
g(1/0)
f
f: A => B+E
g: B => C+E
B+E => C+E
g': B+E => C+E
/ g(x) if x ∈ B g'(x)= | \ x if x ∈ E
有了两个函数f: A => B+E和g': B+E => C+E,你可以安全地在数学意义上把它们组合起来,这就是g(f(x))在编程中所做的,但是它必须先把g提升到g'。考虑一下不确定性,如果你有一个不确定的函数A -> B,你可以用数学的方法描述它,这是一个函数A => Set(B),其中Set(B)是可能结果的集合,例如,如果f(1)可能给予你1,2或3,那么数学上就是f(1) = {1,2,3},尽管在编程时,当要求输入f(1)时,你只能得到其中一个,现在你可以通过写g(f(x))来组合非确定性函数A->B和B->C。结果将为C类型,但它是不确定的。从数学上讲,组合函数A => Set(B)和B => Set(C)会得到A => Set(C)。尽管g只接受B的一个值,但必须将其提升为不确定的值g': Set(B) => Set(C)。例如,g'({1,2})是集合g(1)和g(2)的并集。因此g(f(x))意味着您运行f,获取所有可能结果的集合,并对每个结果运行g。存在两层不确定性,但它们被“扁平化”为一层。全局状态也一样,如果你把每个全局变量都作为函数的参数和结果,你可以认为没有全局变量,每个函数都取所有的全局状态,语言在编写时必须移交状态。一个函数A -> B阅读并可能写入状态S是一个函数(A,S) => (B,S),也可以写成A => (S => (B,S)),正式写起来要复杂一些,但是模式是一样的。输入/输出也可以这样做,我在另一个SO answer中描述过。允许组合“有效”函数的“魔力”是:
g'
A => Set(B)
Set(B)
f(1)
f(1) = {1,2,3}
A->B
B->C
C
B => Set(C)
A => Set(C)
g': Set(B) => Set(C)
g'({1,2})
g(1)
g(2)
S
(A,S) => (B,S)
A => (S => (B,S))
B+E
X
F(X)
B -> F(C)
F(B) -> F(C)
A -> F(B)
return
A
A+E
Set(A)
X -> F(X)
由这三个单子组成的结构称为单子。单子允许描述那些副作用。单子也可能有一些特定的功能,例如异常单子有throw,非确定性单子有fork,状态单子有get/put,IO单子有read/write等。这个故事的寓意是:如果你把随机化、异常、非确定性、输入/输出等特殊效果看作函数结果的一部分,那么每个函数都是引用透明的,命令式编程中的函数实际上是数学函数,但具有非常奇怪的结果类型,这些结果类型也描述了特殊效果,这是纯函数式语言如Haskell所采用的方法。
throw
fork
get/put
read/write
z31licg05#
在数学中,函数不会抛出异常。:)计算机科学中的函数是一段代码,它接受输入,执行某项操作,并可能返回输出,但它可以在这两者之间执行许多操作,它可以获取网页、发送电子邮件、播放视频,等等。在数学中,函数是非常具体的东西,不是别的。函数通常被描述为一台接受输入并吐出输出的“机器”。而计算机科学函数确实接受输入并吐出输出,他们不需要像数学那样精确的“相同的输入总是产生相同的输出(例如,bool IsMyApplicationRunningInFullScreen()返回各种值,而根本没有输入)。
e4eetjau6#
数学函数本质上是声明性的,即它们总是有“是什么”的描述,而计算机科学中的函数是命令性的,即它们有“如何”的描述。参考资料:计算机程序的结构和解释.
6条答案
按热度按时间uemypmqf1#
在函数式编程中,我们有Referential Transparency,这意味着可以用函数的值替换函数,而不需要修改程序。* 这在数学中也是正确的*,但在命令式语言中并不总是正确的*。
主要的区别在于,如果你在数学中调用
f(x)
,你总是得到相同的答案,但是如果你在C中调用f'(x)
,答案可能不一样--相同的参数并不总是返回相同的输出。而且取决于程序中的其他东西(封闭作用域、全局变量、内置函数、状态(如果使用面向对象))。math函数和C函数的另一个区别是,在Math中,您不能创建从非空集到空集的函数(在C中,这将是:你不需要总是返回一些东西),而且,不是所有的函数都是computable(我不知道在数学中是否有类似的东西),你没有无限集的函数(你有有限的内存,所以可能的输入参数集必须是有限的),但是在数学中,你可以定义一个无限集的函数(比如f:N -〉N)和uncountable集合(如f:R -〉R)(在C中你有浮点数,但它们只表示真实的的简化集,这是有限的)。
总结:
在C语言中,您并不总是具有引用透明度。您的函数可能并不总是为相同的输入参数给予相同的输出。您可以拥有为无限输入集定义的数学函数,但在C语言函数中,您的输入是有限的。在C语言函数中,您可以拥有不返回任何值的函数,但在数学中,您不能拥有这种函数(如果你有一个有非空输入集的函数,你必须将每个元素Map到另一个集合中的一个)。
thigvfpy2#
这取决于领域(我不是指功能的领域,我是指学习的领域),也可能取决于语言。
在数学中,对于给定的输入值,一个函数的输入只能Map到一个输出(请记住,垂直线测试);在编程中,这可能并不完全相同,这取决于你在“输入”和“函数逻辑”之间画的线。
例如,假设我们有一个函数兰德(),它读取大气条件以得到一个真正的随机数,再假设一个调用函数将一个整型参数作为排序的乘数,那么下面这个函数是函数吗?
从数学意义上讲,如果您将mult视为问题的唯一输入,那么它可能不是一个函数,但显然兰德()也提供了输入(尽管rand()在机器代码中总是具有相同的入口点)。
正如您所看到的,如果没有一些大家都同意的标准协议,这些差异实际上是无法客观定义的。
mw3dktmi3#
我认为最重要的区别是数学(和函数式编程)中的函数不能改变状态,而(命令式)编程函数可以。
omhiaaxx4#
其他答案都是正确的--这是两件不同的事情,相反,我将证明它们是相关的,我将用
->
表示编程函数,用=>
表示数学函数。假设你有一种支持异常的语言。在这种情况下,你可以把一个编程函数
A -> B
想象成一个数学函数A => B + E
,其中“B + E”表示B
类型的东西,或者E
类型的东西。你的语言有两个从函数返回的关键字,“return”和“throw”。现在,您可以通过编写
g(f(x))
来组合两个函数f: A -> B
和g: B -> C
。这是一个接受A并返回C的函数。您可以在许多语言(如Java或Python)中执行此操作。实际上,如果f(x)
抛出异常,g
不会被调用,异常会被传播--想想g(1/0)
,语言会处理这个问题,你不需要检查f
的结果是否是一个异常。数学上的描述方式是,虽然f: A => B+E
和g: B => C+E
,但语言将函数g“提升”为B+E => C+E
。g
现在是一个可能发生异常的函数,但它只会传播异常。换句话说,定义
g': B+E => C+E
为有了两个函数
f: A => B+E
和g': B+E => C+E
,你可以安全地在数学意义上把它们组合起来,这就是g(f(x))
在编程中所做的,但是它必须先把g
提升到g'
。考虑一下不确定性,如果你有一个不确定的函数
A -> B
,你可以用数学的方法描述它,这是一个函数A => Set(B)
,其中Set(B)
是可能结果的集合,例如,如果f(1)
可能给予你1,2或3,那么数学上就是f(1) = {1,2,3}
,尽管在编程时,当要求输入f(1)
时,你只能得到其中一个,现在你可以通过写g(f(x))
来组合非确定性函数A->B
和B->C
。结果将为C
类型,但它是不确定的。从数学上讲,组合函数A => Set(B)
和B => Set(C)
会得到A => Set(C)
。尽管g
只接受B
的一个值,但必须将其提升为不确定的值g': Set(B) => Set(C)
。例如,g'({1,2})
是集合g(1)
和g(2)
的并集。因此g(f(x))
意味着您运行f
,获取所有可能结果的集合,并对每个结果运行g
。存在两层不确定性,但它们被“扁平化”为一层。全局状态也一样,如果你把每个全局变量都作为函数的参数和结果,你可以认为没有全局变量,每个函数都取所有的全局状态,语言在编写时必须移交状态。一个函数
A -> B
阅读并可能写入状态S
是一个函数(A,S) => (B,S)
,也可以写成A => (S => (B,S))
,正式写起来要复杂一些,但是模式是一样的。输入/输出也可以这样做,我在另一个SO answer中描述过。
允许组合“有效”函数的“魔力”是:
B
转换为B+E
或Set(B)
。我将类型X
的有效版本表示为F(X)
。B -> F(C)
到F(B) -> F(C)
中,允许组合函数A -> F(B)
和B -> F(C)
。return
必须将普通值A
转换为A+E
,或者单例值Set(A)
,所以它的类型必须是X -> F(X)
。由这三个单子组成的结构称为单子。单子允许描述那些副作用。单子也可能有一些特定的功能,例如异常单子有
throw
,非确定性单子有fork
,状态单子有get/put
,IO单子有read/write
等。这个故事的寓意是:如果你把随机化、异常、非确定性、输入/输出等特殊效果看作函数结果的一部分,那么每个函数都是引用透明的,命令式编程中的函数实际上是数学函数,但具有非常奇怪的结果类型,这些结果类型也描述了特殊效果,这是纯函数式语言如Haskell所采用的方法。
z31licg05#
在数学中,函数不会抛出异常。:)
计算机科学中的函数是一段代码,它接受输入,执行某项操作,并可能返回输出,但它可以在这两者之间执行许多操作,它可以获取网页、发送电子邮件、播放视频,等等。
在数学中,函数是非常具体的东西,不是别的。函数通常被描述为一台接受输入并吐出输出的“机器”。而计算机科学函数确实接受输入并吐出输出,他们不需要像数学那样精确的“相同的输入总是产生相同的输出(例如,bool IsMyApplicationRunningInFullScreen()返回各种值,而根本没有输入)。
e4eetjau6#
数学函数本质上是声明性的,即它们总是有“是什么”的描述,而计算机科学中的函数是命令性的,即它们有“如何”的描述。
参考资料:计算机程序的结构和解释.