在数学和编程中,函数有什么区别?
在数学和编程中,函数有什么区别?
数学函数的定义是:将来自一个集合(A)的元素映射到另一个集合(B)的关系,将第一个集合的每个元素与另一个集合中的一个元素对应。 在 C(以及其他编程语言)中,这也是真实的,您有输入集和输出集(几乎总是只有一个)。
主要的区别在于,如果您在数学中调用 f(x)
,则将始终获得相同的答案,但如果您在 C 中调用 f'(x)
,则答案可能不相同 - 相同的参数不总是返回相同的输出。非函数式语言中的函数可能不仅取决于您提供给它们的参数,还取决于程序中的其他事物(封闭作用域、全局变量、内置变量、状态(如果使用面向对象)。
int giveRandAtmosWithMul(int mult)
{
return mult * rand();
}
我认为最重要的区别在于,数学中的函数(以及函数式编程)不能改变状态,而(命令式)编程函数可以。
->
表示编程函数,用=>
表示数学函数。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
/ 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
。有两层非确定性,但它们被“展平”成一层。S
的函数 A -> B
是一个函数 (A,S) => (B,S)
,也可以写成 A => (S => (B,S))
。正式地写这个更复杂,但是它是相同的模式。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所采取的方法。
在数学中,函数不会抛出异常。 :)
在计算机科学中,函数是一段代码,它接受输入,执行某些操作,并可能返回输出,但在此之间它可以执行许多其他操作。它可以获取网页、发送电子邮件、播放视频等等。
在数学中,函数是非常具体且独特的东西。函数通常被描述为一个“机器”,它接受输入并产生输出。虽然计算机科学函数确实接受输入并产生输出,但它们不必像数学所要求的那样具有“相同的输入始终产生相同的输出”的精确性(例如,bool IsMyApplicationRunningInFullScreen() 在没有任何输入的情况下返回各种值)。