scala 函数式编程中如何存在时间函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7267760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can a time function exist in functional programming?
提问by Nawaz
I've to admit that I don't know much about functional programming. I read about it from here and there, and so came to know that in functional programming, a function returns the same output, for same input, no matter how many times the function is called. It's exactly like a mathematical function which evaluates to the same output for the same value of the input parameters which involves in the function expression.
我必须承认我对函数式编程了解不多。我从这里和那里读到了它,所以我知道在函数式编程中,对于相同的输入,无论函数被调用多少次,函数都会返回相同的输出。它就像一个数学函数,它针对函数表达式中涉及的输入参数的相同值计算出相同的输出。
For example, consider this:
例如,考虑这个:
f(x,y) = x*x + y; // It is a mathematical function
No matter how many times you use f(10,4), its value will always be 104. As such, wherever you've written f(10,4), you can replace it with 104, without altering the value of the whole expression. This property is referred to as referential transparencyof an expression.
无论你使用多少次f(10,4),它的价值永远是104。因此,无论您在何处编写f(10,4),都可以将其替换为104,而不会改变整个表达式的值。此属性称为表达式的引用透明度。
As Wikipedia says (link),
正如维基百科所说(链接),
Conversely, in functional code, the output value of a function depends only on the arguments that are input to the function, so calling a function f twice with the same value for an argument x will produce the same result f(x) both times.
相反,在函数代码中,函数的输出值仅取决于输入到函数的参数,因此使用参数 x 的相同值调用函数 f 两次将产生相同的结果 f(x) 两次。
Can a time function (which returns the currenttime) exist in functional programming?
函数式编程中可以存在时间函数(返回当前时间)吗?
If yes, then how can it exist? Does it not violate the principle of functional programming? It particularly violates referential transparencywhich is one of the property of functional programming (if I correctly understand it).
Or if no, then how can one know the current time in functional programming?
如果是,那么它怎么可能存在?是不是违反了函数式编程的原则?它特别违反了引用透明性,这是函数式编程的属性之一(如果我理解正确的话)。
或者如果没有,那么如何知道函数式编程中的当前时间?
采纳答案by dainichi
Another way to explain it is this: no functioncan get the current time (since it keeps changing), but an actioncan get the current time. Let's say that getClockTimeis a constant (or a nullary function, if you like) which represents the actionof getting the current time. This actionis the same every time no matter when it is used so it is a real constant.
另一种解释是:没有函数可以获取当前时间(因为它一直在变化),但是一个动作可以获取当前时间。假设这getClockTime是一个常数(或一个空函数,如果你喜欢),它代表获取当前时间的动作。无论何时使用该动作,每次都是相同的,因此它是一个真正的常数。
Likewise, let's say printis a function which takes some time representation and prints it to the console. Since function calls cannot have side effects in a pure functional language, we instead imagine that it is a function which takes a timestamp and returns the actionof printing it to the console. Again, this is a real function, because if you give it the same timestamp, it will return the same actionof printing it every time.
同样,假设print是一个需要一些时间表示并将其打印到控制台的函数。由于函数调用在纯函数式语言中不会有副作用,我们可以想象它是一个函数,它接受一个时间戳并将打印它的操作返回到控制台。同样,这是一个真正的函数,因为如果你给它相同的时间戳,它每次都会返回相同的打印动作。
Now, how can you print the current time to the console? Well, you have to combine the two actions. So how can we do that? We cannot just pass getClockTimeto print, since print expects a timestamp, not an action. But we can imagine that there is an operator, >>=, which combinestwo actions, one which gets a timestamp, and one which takes one as argument and prints it. Applying this to the actions previously mentioned, the result is... tadaaa... a new action which gets the current time and prints it. And this is incidentally exactly how it is done in Haskell.
现在,如何将当前时间打印到控制台?那么,你必须结合这两个动作。那我们怎么做呢?我们不能只传递getClockTime给print,因为 print 需要一个时间戳,而不是一个动作。但是我们可以想象有一个操作符,>>=,它结合了两个动作,一个获取时间戳,一个将一个作为参数并打印出来。将此应用于前面提到的操作,结果是... tadaaa... 一个新的操作,它获取当前时间并打印出来。顺便说一句,这正是在 Haskell 中完成的方式。
Prelude> System.Time.getClockTime >>= print
Fri Sep 2 01:13:23 東京 (標準時) 2011
So, conceptually, you can view it in this way: A pure functional program does not perform any I/O, it defines an action, which the runtime system then executes. The actionis the same every time, but the result of executing it depends on the circumstances of when it is executed.
因此,从概念上讲,您可以这样看待它:纯函数式程序不执行任何 I/O,它定义了一个操作,然后运行时系统执行该操作。该动作是相同的每一次,但在执行它的结果取决于在执行时的情况。
I don't know if this was any clearer than the other explanations, but it sometimes helps me to think of it this way.
我不知道这是否比其他解释更清楚,但它有时会帮助我以这种方式思考。
回答by Carsten
Yes and no.
是和否。
Different functional programming languages solve them differently.
不同的函数式编程语言以不同的方式解决它们。
In Haskell (a very pure one) all this stuff has to happen in something called the I/O Monad- see here.
在 Haskell(一个非常纯粹的)中,所有这些东西都必须在称为I/O Monad 的东西中发生- 请参见此处。
You can think of it as getting another input (and output) into your function (the world-state) or easier as a place where "impureness" like getting the changing time happens.
您可以将其视为将另一个输入(和输出)添加到您的函数(世界状态)中,或者更容易地将其视为“不纯”(例如获取不断变化的时间)发生的地方。
Other languages like F# just have some impureness built in and so you can have a function that returns different values for the same input - just like normalimperative languages.
其他语言(如 F#)只是内置了一些不纯性,因此您可以使用一个函数为相同的输入返回不同的值 - 就像普通的命令式语言一样。
As Jeffrey Burka mentioned in his comment: Here is the nice introduction to the I/O Monadstraight from the Haskell wiki.
正如 Jeffrey Burka 在他的评论中提到的:这是直接来自 Haskell wiki 的对 I/O Monad 的很好的介绍。
回答by fuz
In Haskell one uses a construct called monadto handle side effects. A monad basically means that you encapsulate values into a container and have some functions to chain functions from values to values inside a container. If our container has the type:
在 Haskell 中,使用一种称为monad的构造来处理副作用。monad 基本上意味着您将值封装到一个容器中,并有一些函数将函数从值链接到容器内的值。如果我们的容器具有以下类型:
data IO a = IO (RealWorld -> (a,RealWorld))
we can safely implement IO actions. This type means: An action of type IOis a function, that takes a token of type RealWorldand returns a new token, together with a result.
我们可以安全地执行 IO 操作。这种类型的意思是:类型的动作IO是一个函数,它接受一个类型的标记RealWorld并返回一个新的标记和结果。
The idea behind this is that each IO action mutates the outside state, represented by the magical token RealWorld. Using monads, one can chain multiple functions that mutate the real world together. The most important function of a monad is >>=, pronounced bind:
这背后的想法是每个 IO 操作都会改变外部状态,由神奇的令牌 表示RealWorld。使用 monad,人们可以将多个函数链接在一起,使现实世界发生变异。monad 最重要的功能是>>=,发音为bind:
(>>=) :: IO a -> (a -> IO b) -> IO b
>>=takes one action and a function that takes the result of this action and creates a new action out of this. The return type is the new action. For instance, let's pretend there is a function now :: IO String, which returns a String representing the current time. We can chain it with the function putStrLnto print it out:
>>=采取一个动作和一个函数,该函数接受这个动作的结果并从中创建一个新的动作。返回类型是新操作。例如,假设有一个函数now :: IO String,它返回一个表示当前时间的字符串。我们可以将它与函数链接putStrLn起来打印出来:
now >>= putStrLn
Or written in do-Notation, which is more familiar to an imperative programmer:
或者用do-Notation编写,这是命令式程序员更熟悉的:
do currTime <- now
putStrLn currTime
All this is pure, as we map the mutation and information about the world outside to the RealWorldtoken. So each time, you run this action, you get of course a different output, but the input is not the same: the RealWorldtoken is different.
所有这些都是纯粹的,因为我们将外部世界的突变和信息映射到RealWorld令牌。因此,每次运行此操作时,您当然会得到不同的输出,但输入并不相同:RealWorld令牌不同。
回答by sepp2k
Most functional programming languages are not pure, i.e. they allow functions to not only depend on their values. In those languages it is perfectly possible to have a function returning the current time. From the languages you tagged this question with this applies to Scalaand F#(as well as most other variants of ML).
大多数函数式编程语言都不是纯粹的,即它们允许函数不仅仅依赖于它们的值。在这些语言中,完全有可能让函数返回当前时间。从你标记这个问题的语言来看,这适用于Scala和F#(以及ML 的大多数其他变体)。
In languages like Haskelland Clean, which are pure, the situation is different. In Haskell the current time would not be available through a function, but a so-called IO action, which is Haskell's way of encapsulating side effects.
在像Haskell和Clean这样的纯语言中,情况就不同了。在 Haskell 中,当前时间不会通过函数获得,而是通过所谓的 IO 动作获得,这是 Haskell 封装副作用的方式。
In Clean it would be a function, but the function would take a world value as its argument and return a fresh world value (in addition to the current time) as its result. The type system would make sure that each world value can be used only once (and each function which consumes a world value would produces a new one). This way the time function would have to be called with a different argument each time and thus would be allowed to return a different time each time.
在 Clean 中,它将是一个函数,但该函数将一个世界值作为其参数,并返回一个新的世界值(除了当前时间)作为其结果。类型系统将确保每个世界值只能使用一次(并且每个消耗世界值的函数都会产生一个新的)。这样,时间函数每次都必须用不同的参数调用,因此每次都可以返回不同的时间。
回答by Vlad Patryshev
"Current time" is not a function. It is a parameter. If your code depends on current time, it means your code is parameterized by time.
“当前时间”不是函数。它是一个参数。如果您的代码取决于当前时间,则意味着您的代码是按时间参数化的。
回答by Craig Gidney
It can absolutely be done in a purely functional way. There are several ways to do it, but the simplest is to have the time function return not just the time but also the function you must call to get the next time measurement.
它绝对可以以纯粹的功能方式完成。有几种方法可以做到这一点,但最简单的方法是让时间函数不仅返回时间,还返回您必须调用以获取下一次测量的函数。
In C# you could implement it like this:
在 C# 中,您可以像这样实现它:
// Exposes mutable time as immutable time (poorly, to illustrate by example)
// Although the insides are mutable, the exposed surface is immutable.
public class ClockStamp {
public static readonly ClockStamp ProgramStartTime = new ClockStamp();
public readonly DateTime Time;
private ClockStamp _next;
private ClockStamp() {
this.Time = DateTime.Now;
}
public ClockStamp NextMeasurement() {
if (this._next == null) this._next = new ClockStamp();
return this._next;
}
}
(Keep in mind that this is an example meant to be simple, not practical. In particular, the list nodes can't be garbage collected because they are rooted by ProgramStartTime.)
(请记住,这是一个简单的示例,并不实用。特别是,列表节点不能被垃圾收集,因为它们以 ProgramStartTime 为根。)
This 'ClockStamp' class acts like an immutable linked list, but really the nodes are generated on demand so they can contain the 'current' time. Any function that wants to measure the time should have a 'clockStamp' parameter and must also return its last time measurement in its result (so the caller doesn't see old measurements), like this:
这个“ClockStamp”类就像一个不可变的链表,但实际上节点是按需生成的,因此它们可以包含“当前”时间。任何想要测量时间的函数都应该有一个“clockStamp”参数,并且还必须在其结果中返回其最后一次测量(因此调用者不会看到旧的测量),如下所示:
// Immutable. A result accompanied by a clockstamp
public struct TimeStampedValue<T> {
public readonly ClockStamp Time;
public readonly T Value;
public TimeStampedValue(ClockStamp time, T value) {
this.Time = time;
this.Value = value;
}
}
// Times an empty loop.
public static TimeStampedValue<TimeSpan> TimeALoop(ClockStamp lastMeasurement) {
var start = lastMeasurement.NextMeasurement();
for (var i = 0; i < 10000000; i++) {
}
var end = start.NextMeasurement();
var duration = end.Time - start.Time;
return new TimeStampedValue<TimeSpan>(end, duration);
}
public static void Main(String[] args) {
var clock = ClockStamp.ProgramStartTime;
var r = TimeALoop(clock);
var duration = r.Value; //the result
clock = r.Time; //must now use returned clock, to avoid seeing old measurements
}
Of course, it's a bit inconvenient to have to pass that last measurement in and out, in and out, in and out. There are many ways to hide the boilerplate, especially at the language design level. I think Haskell uses this sort of trick and then hides the ugly parts by using monads.
当然,必须把最后一次测量进进出出,进进出出,进进出出,有点不方便。有很多方法可以隐藏样板,尤其是在语言设计级别。我认为 Haskell 使用了这种技巧,然后通过使用 monad 隐藏了丑陋的部分。
回答by Jeffrey Aguilera
I am surprised that none of the answers or comments mention coalgebras or coinduction. Usually, coinduction is mentioned when reasoning about infinite data structures, but it is also applicable to an endless stream of observations, such as a time register on a CPU. A coalgebra models hidden state; and coinduction models observingthat state. (Normal induction models constructingstate.)
我很惊讶没有一个答案或评论提到余代数或联合归纳。通常,在对无限数据结构进行推理时会提到联合归纳,但它也适用于无穷无尽的观察数据,例如 CPU 上的时间寄存器。一个代数模型隐藏状态;以及观察该状态的联合归纳模型。(正态归纳模型构建状态。)
This is a hot topic in Reactive Functional Programming. If you're interested in this sort of stuff, read this: http://digitalcommons.ohsu.edu/csetech/91/(28 pp.)
这是反应式函数式编程中的热门话题。如果您对此类内容感兴趣,请阅读:http: //digitalcommons.ohsu.edu/csetech/91/(28 页)
回答by Conal
Yes, it's possible for a pure function to return the time, if it's given that time as a parameter. Different time argument, different time result. Then form other functions of time as well and combine them with a simple vocabulary of function(-of-time)-transforming (higher-order) functions. Since the approach is stateless, time here can be continuous (resolution-independent) rather than discrete, greatly boosting modularity. This intuition is the basis of Functional Reactive Programming (FRP).
是的,如果将时间作为参数给出,纯函数可以返回时间。不同的时间争论,不同的时间结果。然后也形成其他时间函数,并将它们与函数(时间)转换(高阶)函数的简单词汇表结合起来。由于该方法是无状态的,这里的时间可以是连续的(与分辨率无关)而不是离散的,极大地提高了模块化。这种直觉是功能反应式编程 (FRP) 的基础。
回答by MduSenthil
Yes! You are correct! Now() or CurrentTime() or any method signature of such flavour is not exhibiting referential transparency in one way. But by instruction to the compiler it is parameterized by a system clock input.
是的!你是对的!Now() 或 CurrentTime() 或任何此类风格的方法签名不会以一种方式表现出引用透明性。但是通过编译器的指令,它由系统时钟输入参数化。
By output, Now() might look like not following referential transparency. But actual behaviour of the system clock and the function on top of it is adheres to referential transparency.
通过输出,Now() 可能看起来不遵循引用透明性。但是系统时钟的实际行为及其之上的功能是遵循引用透明性的。
回答by Ankur
Yes, a getting time function can exist in functional programming using a slightly modified version on functional programming known as impure functional programming (the default or the main one is pure functional programming).
是的,函数式编程中可以存在获取时间函数,使用函数式编程的稍微修改版本,称为不纯函数式编程(默认或主要是纯函数式编程)。
In case of getting the time (or reading file, or launching missile) the code needs to interact with the outer world to get the job done and this outer world is not based on the pure foundations of functional programming. To allow a pure functional programming world to interact with this impure outside world, people have introduced impure functional programming. After all, software which doesn't interact with the outside world isn't any useful other than doing some mathematical computations.
在获取时间(或读取文件,或发射导弹)的情况下,代码需要与外部世界交互才能完成工作,而这个外部世界并非基于函数式编程的纯粹基础。为了让纯函数式编程世界与这个不纯的外部世界交互,人们引入了非纯函数式编程。毕竟,不与外界交互的软件除了进行一些数学计算外没有任何用处。
Few functional programming programming languages have this impurity feature inbuilt in them such that it is not easy to separate out which code is impure and which is pure (like F#, etc.) and some functional programming languages make sure that when you do some impure stuff that code is clearly stand out as compared to pure code, like Haskell.
很少有函数式编程语言具有这种内置的不纯特性,因此不容易区分哪些代码是不纯的,哪些是纯的(如 F# 等),并且一些函数式编程语言确保当你做一些不纯的东西时与像 Haskell 这样的纯代码相比,该代码显然很突出。
Another interesting way to see this would be that your get time function in functional programming would take a "world" object which has the current state of the world like time, number of people living in the world, etc. Then getting time from which world object would be always pure i.e you pass in the same world state you will always get the same time.
另一个有趣的方式是,您在函数式编程中的获取时间函数将采用一个“世界”对象,该对象具有世界的当前状态,例如时间、生活在世界上的人数等。然后从哪个世界获取时间对象将始终是纯的,即您以相同的世界状态传递,您将始终获得相同的时间。

