我必须承认我对函数式编程了解不多。我从这里和那里读到它,所以开始知道在函数式编程中,一个函数返回相同的输出,对于相同的输入,无论函数被调用多少次。它就像一个数学函数,对于函数表达式中包含的输入参数的相同值,计算出相同的输出。

例如,考虑这个:

f(x,y) = x*x + y; // It is a mathematical function

不管你用了多少次f(10,4)它的值总是104。因此,无论你在哪里写f(10,4),你都可以用104替换它,而不改变整个表达式的值。此属性称为表达式的引用透明性。

正如维基百科所说,

相反,在函数式代码中,函数的输出值只取决于函数的输入参数,因此调用函数f两次,参数x的值相同,两次将产生相同的结果f(x)。

函数式编程中是否存在时间函数(返回当前时间)?

如果是,那它怎么可能存在?它是否违反了函数式编程的原则?它尤其违反了引用透明性,这是函数式编程的特性之一(如果我理解正确的话)。 如果没有,那么在函数式编程中如何知道当前时间呢?


当前回答

不引入计划生育的其他概念就可以回答这个问题。

可能性1:time作为函数参数

一门语言包括

语言核心和 标准库。

引用透明性是语言核心的属性,而不是标准库的属性。它绝不是用那种语言编写的程序的属性。

使用OP的符号,应该有一个函数

f(t) = t*v0 + x0; // mathematical function that knows current time

他们会要求标准库获取当前时间,比如1.23,并以该值作为参数f(1.23)(或者只是1.23*v0 + x0,参考透明!)来计算函数。这样代码就能知道当前时间。

可能性2:返回值为时间

回答OP的问题:

函数式编程中是否存在时间函数(返回当前时间)?

是的,但是这个函数必须有一个参数,你必须用不同的输入来计算它,这样它就会返回不同的当前时间,否则它就违反了FP的原则。

f(s) = t(s)*v0 + x0; // mathematical function t(s) returns current time

这是我上面所描述的另一种方法。但话又说回来,首先获取这些不同输入的问题仍然归结为标准库。

可能性3:函数式响应式编程

其思想是函数t()计算为与函数t2配对的当前时间。当需要当前时间时,调用t2(),它会给函数t3,以此类推

(x, t2) = t(); // it's x o'clock now
...
(x2, t3) = t2(); // now it's already x2 o'clock
...
t(); x; // both evaluate to the initial time, referential transparency!

关于FP还有更多,但我认为这超出了op的范围。例如,如何要求标准库计算一个函数,并以纯函数的方式对其返回值进行操作:这是关于副作用而不是参考透明度的。

其他回答

您正在讨论函数式编程中一个非常重要的主题,即执行I/O。许多纯语言是通过使用嵌入式领域特定语言来实现的,例如,一种子语言,其任务是编码可以产生结果的动作。

例如,Haskell运行时希望我定义一个名为main的操作,该操作由组成程序的所有操作组成。运行时然后执行此操作。大多数情况下,这样做只会执行纯代码。运行时将不时使用计算出的数据执行I/O,并将数据反馈回纯代码。

You might complain that this sounds like cheating, and in a way it is: by defining actions and expecting the runtime to execute them, the programmer can do everything a normal program can do. But Haskell's strong type system creates a strong barrier between pure and "impure" parts of the program: you cannot simply add, say, two seconds to the current CPU time, and print it, you have to define an action that results in the current CPU time, and pass the result on to another action that adds two seconds and prints the result. Writing too much of a program is considered bad style though, because it makes it hard to infer which effects are caused, compared to Haskell types that tell us everything we can know about what a value is.

示例:clock_t c = time(NULL);Printf ("%d\n", c + 2);在Haskell中,vs. main = getCPUTime >>= \ C -> print (C + 2*1000*1000*1000*1000)操作符>>=用于组合动作,将第一个动作的结果传递给产生第二个动作的函数。这看起来很神秘,Haskell编译器支持语法糖,允许我们编写后面的代码如下:

type Clock = Integer -- To make it more similar to the C code

-- An action that returns nothing, but might do something
main :: IO ()
main = do
    -- An action that returns an Integer, which we view as CPU Clock values
    c <- getCPUTime :: IO Clock
    -- An action that prints data, but returns nothing
    print (c + 2*1000*1000*1000*1000) :: IO ()

后者看起来很有必要,不是吗?

是的,函数式编程中可以存在一个获得时间的函数,它使用了函数式编程的一个稍微修改过的版本,称为非纯函数式编程(默认的或主要的是纯函数式编程)。

在获取时间(或读取文件,或发射导弹)的情况下,代码需要与外部世界进行交互以完成工作,而这个外部世界并不是基于函数式编程的纯粹基础。为了允许纯函数式编程世界与这个不纯的外部世界进行交互,人们引入了不纯函数式编程。毕竟,不与外部世界交互的软件除了做一些数学计算之外没有任何用处。

很少有函数式编程语言具有这种内嵌的不纯特性,这样就不容易区分哪些代码是不纯的,哪些是纯的(如f#等),而一些函数式编程语言确保当你做一些不纯的事情时,代码与纯代码相比明显突出,如Haskell。

另一种有趣的方式是,函数式编程中的get time函数将接受一个“world”对象,该对象具有世界的当前状态,如时间、生活在世界中的人数等。然后从世界对象中获取时间,这个世界对象总是纯的,即你在相同的世界状态下通过,你将总是得到相同的时间。

大多数函数式编程语言都不是纯粹的,也就是说,它们允许函数不仅依赖于它们的值。在这些语言中,完全有可能有一个返回当前时间的函数。从你标记这个问题的语言中,这适用于Scala和f#(以及ML的大多数其他变体)。

在Haskell和Clean等纯语言中,情况就不同了。在Haskell中,当前时间不是通过函数,而是通过所谓的IO操作,这是Haskell封装副作用的方式。

在Clean中,它将是一个函数,但该函数将以一个世界值作为参数,并返回一个新的世界值(除了当前时间)作为结果。类型系统将确保每个世界值只能使用一次(并且每个消耗世界值的函数将产生一个新的世界值)。这样,每次调用time函数时都必须使用不同的参数,因此允许每次返回不同的时间。

不引入计划生育的其他概念就可以回答这个问题。

可能性1:time作为函数参数

一门语言包括

语言核心和 标准库。

引用透明性是语言核心的属性,而不是标准库的属性。它绝不是用那种语言编写的程序的属性。

使用OP的符号,应该有一个函数

f(t) = t*v0 + x0; // mathematical function that knows current time

他们会要求标准库获取当前时间,比如1.23,并以该值作为参数f(1.23)(或者只是1.23*v0 + x0,参考透明!)来计算函数。这样代码就能知道当前时间。

可能性2:返回值为时间

回答OP的问题:

函数式编程中是否存在时间函数(返回当前时间)?

是的,但是这个函数必须有一个参数,你必须用不同的输入来计算它,这样它就会返回不同的当前时间,否则它就违反了FP的原则。

f(s) = t(s)*v0 + x0; // mathematical function t(s) returns current time

这是我上面所描述的另一种方法。但话又说回来,首先获取这些不同输入的问题仍然归结为标准库。

可能性3:函数式响应式编程

其思想是函数t()计算为与函数t2配对的当前时间。当需要当前时间时,调用t2(),它会给函数t3,以此类推

(x, t2) = t(); // it's x o'clock now
...
(x2, t3) = t2(); // now it's already x2 o'clock
...
t(); x; // both evaluate to the initial time, referential transparency!

关于FP还有更多,但我认为这超出了op的范围。例如,如何要求标准库计算一个函数,并以纯函数的方式对其返回值进行操作:这是关于副作用而不是参考透明度的。

如果是,那它怎么可能存在?这难道不违反原则吗 函数式编程吗?它尤其违反了参照原则 透明度

它的存在不是纯粹的功能性的。

如果不是,那么如何知道当前时间是泛函的 编程吗?

首先,了解如何在计算机上检索时间可能是有用的。从本质上讲,有一个板载电路来记录时间(这就是电脑通常需要一个小电池的原因)。然后可能会有一些内部进程在某个内存寄存器上设置时间的值。这本质上可以归结为CPU可以检索到的值。


对于Haskell,有一个“IO动作”的概念,它表示一种类型,可以执行一些IO进程。因此,我们不引用时间值,而是引用IO时间值。所有这些都是纯功能性的。我们引用的不是时间,而是“读取时间寄存器的值”之类的东西。

当我们实际执行Haskell程序时,IO操作将实际发生。