How can a time function exist in functional programming?

后端 未结 15 483
Happy的楠姐
Happy的楠姐 2020-12-04 04:26

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 retu

15条回答
  •  春和景丽
    2020-12-04 05:02

    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:

    // 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.)

    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:

    // Immutable. A result accompanied by a clockstamp
    public struct TimeStampedValue {
        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 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(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.

提交回复
热议问题