我必须承认我对函数式编程了解不多。我从这里和那里读到它,所以开始知道在函数式编程中,一个函数返回相同的输出,对于相同的输入,无论函数被调用多少次。它就像一个数学函数,对于函数表达式中包含的输入参数的相同值,计算出相同的输出。
例如,考虑这个:
f(x,y) = x*x + y; // It is a mathematical function
不管你用了多少次f(10,4)它的值总是104。因此,无论你在哪里写f(10,4),你都可以用104替换它,而不改变整个表达式的值。此属性称为表达式的引用透明性。
正如维基百科所说,
相反,在函数式代码中,函数的输出值只取决于函数的输入参数,因此调用函数f两次,参数x的值相同,两次将产生相同的结果f(x)。
函数式编程中是否存在时间函数(返回当前时间)?
如果是,那它怎么可能存在?它是否违反了函数式编程的原则?它尤其违反了引用透明性,这是函数式编程的特性之一(如果我理解正确的话)。
如果没有,那么在函数式编程中如何知道当前时间呢?
这完全可以用纯功能的方式来完成。有几种方法可以做到这一点,但最简单的方法是让time函数不仅返回时间,还返回您必须调用以获得下一次时间测量的函数。
在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;
}
}
(请记住,这是一个简单的示例,而不是实际的示例。特别是,列表节点不能被垃圾收集,因为它们是由ProgramStartTime根的。)
这个“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
}
当然,这有点不方便,必须把最后的测量输入输出,输入输出,输入输出。隐藏样板文件的方法有很多,尤其是在语言设计级别。我认为Haskell使用这种技巧,然后通过使用单子隐藏丑陋的部分。