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

例如,考虑这个:

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

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

正如维基百科所说,

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

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

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


当前回答

你的问题合并了计算机语言的两种相关衡量标准:函数式/命令式和纯粹/不纯粹。

函数式语言定义了函数的输入和输出之间的关系,命令式语言按照特定的执行顺序描述了特定的操作。

纯粹的语言不会产生或依赖副作用,而不纯粹的语言则自始至终都在使用副作用。

百分之百纯粹的程序基本上是无用的。他们可能会进行有趣的计算,但因为他们没有副作用,他们没有输入或输出,所以你永远不会知道他们计算了什么。

要想有用,一个程序至少要有一点不纯。使纯程序有用的一种方法是将它放在一个薄的非纯包装器中。比如下面这个未经测试的Haskell程序:

-- this is a pure function, written in functional style.
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

-- This is an impure wrapper around the pure function, written in imperative style
-- It depends on inputs and produces outputs.
main = do
    putStrLn "Please enter the input parameter"
    inputStr <- readLine
    putStrLn "Starting time:"
    getCurrentTime >>= print
    let inputInt = read inputStr    -- this line is pure
    let result = fib inputInt       -- this is also pure
    putStrLn "Result:"
    print result
    putStrLn "Ending time:"
    getCurrentTime >>= print

其他回答

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

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

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

你的问题合并了计算机语言的两种相关衡量标准:函数式/命令式和纯粹/不纯粹。

函数式语言定义了函数的输入和输出之间的关系,命令式语言按照特定的执行顺序描述了特定的操作。

纯粹的语言不会产生或依赖副作用,而不纯粹的语言则自始至终都在使用副作用。

百分之百纯粹的程序基本上是无用的。他们可能会进行有趣的计算,但因为他们没有副作用,他们没有输入或输出,所以你永远不会知道他们计算了什么。

要想有用,一个程序至少要有一点不纯。使纯程序有用的一种方法是将它放在一个薄的非纯包装器中。比如下面这个未经测试的Haskell程序:

-- this is a pure function, written in functional style.
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

-- This is an impure wrapper around the pure function, written in imperative style
-- It depends on inputs and produces outputs.
main = do
    putStrLn "Please enter the input parameter"
    inputStr <- readLine
    putStrLn "Starting time:"
    getCurrentTime >>= print
    let inputInt = read inputStr    -- this line is pure
    let result = fib inputInt       -- this is also pure
    putStrLn "Result:"
    print result
    putStrLn "Ending time:"
    getCurrentTime >>= print

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

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

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

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


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

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

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

您正在讨论函数式编程中一个非常重要的主题,即执行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 ()

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