순전히 기능적인 방식으로 수행 할 수 있습니다. 여러 가지 방법이 있지만 가장 간단한 방법은 시간 함수가 시간뿐만 아니라 다음에 측정 할 때 호출해야하는 함수를 반환하는 것 입니다.
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은 이런 종류의 트릭을 사용하고 모나드를 사용하여 못생긴 부분을 숨기고 있다고 생각합니다.