How can a time function exist in functional programming?

后端 未结 15 455
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:00

    In Haskell one uses a construct called monad to 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:

    data IO a = IO (RealWorld -> (a,RealWorld))
    

    we can safely implement IO actions. This type means: An action of type IO is a function, that takes a token of type RealWorld and returns a new token, together with a result.

    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 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 putStrLn to print it out:

    now >>= putStrLn
    

    Or written in do-Notation, which is more familiar to an imperative programmer:

    do currTime <- now
       putStrLn currTime
    

    All this is pure, as we map the mutation and information about the world outside to the RealWorld token. So each time, you run this action, you get of course a different output, but the input is not the same: the RealWorld token is different.

    0 讨论(0)
  • 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<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.

    0 讨论(0)
  • 2020-12-04 05:02

    If yes, then how can it exist? Does it not violate the principle of functional programming? It particularly violates referential transparency

    It does not exist in a purely functional sense.

    Or if no, then how can one know the current time in functional programming?

    It may first be useful to know how a time is retrieved on a computer. Essentially there is onboard circuitry that keeps track of the time (which is the reason a computer would usually need a small cell battery). Then there might be some internal process that sets the value of time at a certain memory register. Which essentially boils down to a value that can be retrieved by the CPU.


    For Haskell, there is a concept of an 'IO action' which represents a type that can be made to carry out some IO process. So instead of referencing a time value we reference a IO Time value. All this would be purely functional. We aren't referencing time but something along the lines of 'read the value of the time register'.

    When we actually execute the Haskell program, the IO action would actually take place.

    0 讨论(0)
  • 2020-12-04 05:03

    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 Scala and F# (as well as most other variants of ML).

    In languages like Haskell and 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.

    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.

    0 讨论(0)
  • 2020-12-04 05:04

    "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.

    0 讨论(0)
  • 2020-12-04 05:04

    It can be answered without introducing other concepts of FP.

    Possibility 1: time as function argument

    A language consists of

    1. language core and
    2. standard library.

    Referential transparency is a property of language core, but not standard library. By no means is it a property of programs written in that language.

    Using OP's notation, should one have a function

    f(t) = t*v0 + x0; // mathematical function that knows current time
    

    They would ask standard library to get current time, say 1.23, and compute the function with that value as an argument f(1.23) (or just 1.23*v0 + x0, referential transparency!). That way the code gets to know the current time.

    Possibility 2: time as return value

    Answering OP's question:

    Can a time function (which returns the current time) exist in functional programming?

    Yes, but that function has to have an argument and you would have to compute it with different inputs so it returns different current time, otherwise it would violate the principals of FP.

    f(s) = t(s)*v0 + x0; // mathematical function t(s) returns current time
    

    This is an alternative approach to what I've described above. But then again, the question of obtaining those different inputs s in the first place still comes down to standard library.

    Possibility 3: functional reactive programming

    The idea is that function t() evaluates to current time paired with function t2. When one needs current time again later they are to call t2(), it will then give function t3 and so on

    (x, t2) = t(); // it's x o'clock now
    ...
    (x2, t3) = t2(); // now it's already x2 o'clock
    ...
    t(); x; // both evaluate to the initial time, referential transparency!
    

    There's more to FP but I believe it's out of the scope of OP. For example, how does one ask standard library to compute a function and act upon its return value in purely functional way: that one is rather about side effects than referential transparency.

    0 讨论(0)
提交回复
热议问题