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

例如,考虑这个:

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

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

正如维基百科所说,

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

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

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


当前回答

是的!你说对了!Now()或CurrentTime()或任何这种风格的方法签名都没有以某种方式显示引用透明性。但是通过对编译器的指令,它是由系统时钟输入参数化的。

通过输出,Now()可能看起来没有遵循引用透明性。但是系统时钟和它上面的功能的实际行为是坚持的 引用透明性。

其他回答

“当前时间”不是一个函数。它是一个参数。如果您的代码依赖于当前时间,这意味着您的代码是由时间参数化的。

在Haskell中,我们使用一个叫做monad的结构来处理副作用。单子基本上意味着你将值封装到容器中,并在容器中使用一些函数将值与值之间的函数链接起来。如果容器的类型为:

data IO a = IO (RealWorld -> (a,RealWorld))

我们可以安全地实现IO动作。IO类型的动作是一个函数,它接受一个RealWorld类型的令牌,并返回一个新的令牌和结果。

这背后的想法是,每个IO操作都会改变外部状态,由神奇的令牌RealWorld表示。通过使用单子,我们可以将多个函数链接在一起,从而改变现实世界。一个单子最重要的功能是>>=,发音为bind:

(>>=) :: IO a -> (a -> IO b) -> IO b

>>=取一个动作和一个函数,该函数取这个动作的结果并由此创建一个新的动作。返回类型是新动作。例如,假设现在有一个函数::IO String,它返回一个表示当前时间的String。我们可以用putStrLn函数链接它来打印它:

now >>= putStrLn

或者用do-Notation写,这对命令式程序员来说更熟悉:

do currTime <- now
   putStrLn currTime

所有这些都是纯粹的,因为我们将关于外部世界的突变和信息映射到RealWorld令牌。因此,每次运行此操作时,当然会得到不同的输出,但输入是不相同的:RealWorld令牌是不同的。

我很惊讶,没有一个答案或评论提到共代数或共归纳。通常,同归纳法在对无限数据结构进行推理时被提及,但它也适用于无穷无尽的观察流,例如CPU上的时间寄存器。一个协代数模型隐藏状态;同感应模型观察到这种状态。(正常诱导模型构造状态。)

这是响应式函数式编程中的一个热门话题。如果你对这类东西感兴趣,请阅读以下内容:http://digitalcommons.ohsu.edu/csetech/91/(28页)

Richard B. Kieburtz,“响应式函数式编程”(1997)。CSETech。第91篇(链接)

是的!你说对了!Now()或CurrentTime()或任何这种风格的方法签名都没有以某种方式显示引用透明性。但是通过对编译器的指令,它是由系统时钟输入参数化的。

通过输出,Now()可能看起来没有遵循引用透明性。但是系统时钟和它上面的功能的实际行为是坚持的 引用透明性。

是也不是。

不同的函数式编程语言解决这些问题的方法不同。

在Haskell(一个非常纯粹的Haskell)中,所有这些东西都必须发生在一个叫做I/O单子的东西中——看这里。

你可以把它看作是将另一个输入(和输出)输入到你的函数(世界状态)中,或者更简单地认为是“不确定性”发生的地方,比如得到变化的时间。

像f#这样的其他语言只是内置了一些不纯性,所以你可以有一个函数为相同的输入返回不同的值——就像普通的命令式语言一样。

正如杰弗里·伯卡在他的评论中提到的: 下面是来自Haskell wiki的I/O单子的介绍。