我必须承认我对函数式编程了解不多。我从这里和那里读到它,所以开始知道在函数式编程中,一个函数返回相同的输出,对于相同的输入,无论函数被调用多少次。它就像一个数学函数,对于函数表达式中包含的输入参数的相同值,计算出相同的输出。
例如,考虑这个:
f(x,y) = x*x + y; // It is a mathematical function
不管你用了多少次f(10,4)它的值总是104。因此,无论你在哪里写f(10,4),你都可以用104替换它,而不改变整个表达式的值。此属性称为表达式的引用透明性。
正如维基百科所说,
相反,在函数式代码中,函数的输出值只取决于函数的输入参数,因此调用函数f两次,参数x的值相同,两次将产生相同的结果f(x)。
函数式编程中是否存在时间函数(返回当前时间)?
如果是,那它怎么可能存在?它是否违反了函数式编程的原则?它尤其违反了引用透明性,这是函数式编程的特性之一(如果我理解正确的话)。
如果没有,那么在函数式编程中如何知道当前时间呢?
是的,函数式编程中可以存在一个获得时间的函数,它使用了函数式编程的一个稍微修改过的版本,称为非纯函数式编程(默认的或主要的是纯函数式编程)。
在获取时间(或读取文件,或发射导弹)的情况下,代码需要与外部世界进行交互以完成工作,而这个外部世界并不是基于函数式编程的纯粹基础。为了允许纯函数式编程世界与这个不纯的外部世界进行交互,人们引入了不纯函数式编程。毕竟,不与外部世界交互的软件除了做一些数学计算之外没有任何用处。
很少有函数式编程语言具有这种内嵌的不纯特性,这样就不容易区分哪些代码是不纯的,哪些是纯的(如f#等),而一些函数式编程语言确保当你做一些不纯的事情时,代码与纯代码相比明显突出,如Haskell。
另一种有趣的方式是,函数式编程中的get time函数将接受一个“world”对象,该对象具有世界的当前状态,如时间、生活在世界中的人数等。然后从世界对象中获取时间,这个世界对象总是纯的,即你在相同的世界状态下通过,你将总是得到相同的时间。
在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令牌是不同的。