673

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 transparency of an expression.

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.

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

  • If yes, then how can it exist? Does it not violate the principle of functional programming? It particularly violates referential transparency which 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?

glennsl
  • 28,186
  • 12
  • 57
  • 75
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • My immediate thought would be the function takes a method parameter for the time, and the caller simply supplies the current time. This way, supplied with the same arguments it gives the same result, and it is up to the caller to change the argument. – Adam Houldsworth Sep 01 '11 at 08:30
  • 15
    I think most (or all) functional languages are not so strict and combine functional and imperative programming. At least, this is my impression from F#. – Alex F Sep 01 '11 at 08:33
  • 13
    @Adam: How would the caller know the current time in the first place? – Nawaz Sep 01 '11 at 08:35
  • 3
    @Nawaz Oh I see what you are getting at, I thought you were referring to creation of a function that internally used the current time. Well, I'm sure it's not *illegal* to return different values if the condition changes, and a change in time is a change in condition. – Adam Houldsworth Sep 01 '11 at 08:37
  • 33
    @Adam: Actually it is illegal (as in: impossible) in purely functional languages. – sepp2k Sep 01 '11 at 08:49
  • 2
    @sepp2k interesting stuff, so if a purely functional system needed to work with a time element, it would need to be provided externally? As in, taken as an argument. – Adam Houldsworth Sep 01 '11 at 08:52
  • 50
    @Adam: Pretty much. A general purpose language which is pure usually offers some facility to get at the "world state" (i.e. things like the current time, files in a directory etc.) without breaking referential transparency. In Haskell that's the IO monad and in Clean it's the world type. So in those languages a function which needs the current time would either take it as an argument or it would need to return an IO action instead of its actual result (Haskell) or take the world state as its argument (Clean). – sepp2k Sep 01 '11 at 09:00
  • 1
    @Alex your impression is correct F# is multiparadigm with emphasis on FP but you can do pure OO in F# if you so wish – Rune FS Sep 01 '11 at 12:48
  • 16
    When thinking about FP it's easy to forget: a computer is a big chunk of mutable state. FP doesn't change that, it merely conceals it. – Daniel Sep 01 '11 at 14:56
  • 5
    Some languages have a pseudo constant variable such as CURRENT_TIMESTAMP. It's a constant that's different every second. – Mikhail Sep 01 '11 at 15:27
  • 8
    @Mikhail: Hahahaha... that made me laugh. Why people would call it constant in the first place then, whose value changes every second? Just to "feel" consistent? – Nawaz Sep 01 '11 at 15:31
  • 1
    +1 Same thing when dealing with a random number generator in F#. Easy to do but 'impure' – Rangoric Sep 01 '11 at 15:32
  • 2
    @Nawaz, honestly no idea... It's not a "variable" that can vary or be set... so it's a constant, at least for the duration of a single run. – Mikhail Sep 01 '11 at 15:52
  • 1
    Simply consider every previous output of your 'time' function from this current run as part of the input to the function. Thus it can never be called twice with the same inputs during the same run. – David Schwartz Sep 01 '11 at 16:10
  • 2
    @David: Isn't that too much of philosophy and that too, *esoteric* one? :| Moreover, using such esoteric philosophy, even imperative programming can be called functional programming. – Nawaz Sep 01 '11 at 16:13
  • 2
    I would really recommend reading the 1.2 Von Neumann Languages (or really the whole first chapter) in [Introduction to Functional Programming Systems Using Haskell](http://books.google.com/books?id=OPFoJZeI8MEC&printsec=frontcover&dq=Introduction+to+Functional+Programming+Systems+Using+Haskell&hl=en&src=bmrr&ei=4a5fTonQG862tgfSj8mlCw&sa=X&oi=book_result&ct=result&resnum=1&ved=0CCoQ6AEwAA#v=onepage&q&f=false). The author does a *really* great job at explaining why referential transparency is so important to mathematics. – eternalmatt Sep 01 '11 at 16:14
  • 4
    @Mikhail and in Haskell, we call everything - including functions - variables, though changing them is impossible. – fuz Sep 01 '11 at 16:21
  • 9
    You might want to check out [this video](http://ontwik.com/haskell/simon-peyton-jones-a-taste-of-haskell/). He talks about pure functional programming for a while, then he says something like, "Okay, but if we just write completely pure functions all the time, we can never get any input from the user, or produce any output -- our program can't actually *do* anything." A program can't be made entirely of pure (non-IO) functions. But you could have a huge Haskell program that's almost entirely pure functions, and then `main = interact processInput` is the only part that does any IO. – Tyler Sep 01 '11 at 16:34
  • 3
    Great question, but I think it's more fitting on Programmers.SE – zzzzBov Sep 01 '11 at 16:47
  • 2
    @zzzzBov I disagree. IMHO this is a perfectly valid question for SO - it is about a programming topic and not about "meta" stuff. – fuz Sep 01 '11 at 18:11
  • 4
    @FUZxxl, if it were about "meta" stuff it'd belong on [meta]. This is question fits perfectly for [Programmers.SE](http://programmers.stackexchange.com) – zzzzBov Sep 01 '11 at 22:33
  • 3
    any program without IO is useless ... – Dapeng Jun 15 '12 at 02:27
  • even a pure computer with no state still has side-effects, they produce heat, too bad we don't have real Turing machines, only those approximations – Luiz Felipe Sep 02 '17 at 15:34

15 Answers15

365

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.

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 normal imperative languages.

As Jeffrey Burka mentioned in his comment: Here is the nice introduction to the I/O Monad straight from the Haskell wiki.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • 227
    The crucial thing to realise about the IO monad in Haskell is that it is not just a hack to get around this problem; monads are a general solution to the problem of defining a sequence of actions in some context. One possible context is the real world, for which we have the IO monad. Another context is within an atomic transaction, for which we have the STM monad. Yet another context is in the implementation of a procedural algorithm (e.g. Knuth shuffle) as a pure function, for which we have the ST monad. And you can define your own monads too. Monads are a kind of overloadable semicolon. – Paul Johnson Sep 01 '11 at 16:31
  • 2
    I find it useful to not call things like getting the current time "functions" but something like "procedures" (though arguable the Haskell solution is an exception to this). – singpolyma Nov 16 '12 at 18:28
  • from the Haskell perspective classical "procedures" (things that have types like '... -> ()') are somewhat trivial as a pure function with ... -> () cannot do anything at all. – Random Dev Nov 16 '12 at 22:45
  • but in this case this would be something like '() -> ...' (a constant function) and **I** would not call this a procedure - but call it as you wish :D – Random Dev Nov 16 '12 at 22:46
  • 4
    The typical Haskell term is "action". – Sebastian Redl May 31 '15 at 10:40
  • @PaulJohnson I understood monad as even more general than actions in sequence. Aren't List and Option monads too? – dawid Oct 21 '21 at 19:38
  • 1
    @dawid that's true - you could see a list as a sequence and the action just as trivially producing the elements-value. And you could see a option as just a single-element or empty list. - More to the point in Haskell (a language where you don't have statements you proceed one by one - you have expressions where the order of evaluation is not guaranteed - some might not be evaluated at all in Haskell as it's lazy). Monads with their bind allows you to express the operation of processing something in order. – Random Dev Oct 22 '21 at 08:29
190

Another way to explain it is this: no function can get the current time (since it keeps changing), but an action can get the current time. Let's say that getClockTime is a constant (or a nullary function, if you like) which represents the action of getting the current time. This action is the same every time no matter when it is used so it is a real constant.

Likewise, let's say print is 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 action of printing it to the console. Again, this is a real function, because if you give it the same timestamp, it will return the same action of printing it every time.

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 getClockTime to print, since print expects a timestamp, not an action. But we can imagine that there is an operator, >>=, which combines two 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.

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 action is the same every time, but the result of executing it depends on the circumstances of when it is executed.

I don't know if this was any clearer than the other explanations, but it sometimes helps me to think of it this way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dainichi
  • 2,231
  • 1
  • 13
  • 12
  • 43
    It's not convincing to me. You conveniently called `getClockTime` an action instead of a function. Well, if you call so, then call every function *action*, then even imperative programming would become functional programmming. Or maybe, you would like to call it *actional* programmming. – Nawaz Sep 01 '11 at 16:54
  • 101
    @Nawaz: The key thing to note here is that you cannot execute an action from within a function. You can only combine actions and functions together to make new actions. The only way of executing an action is to compose it into your `main` action. This allows pure functional code to be separated from imperative code, and this separation is enforced by the type system. Treating actions as first class objects also allow you to pass them around and build your own "control structures". – hammar Sep 01 '11 at 18:25
  • 6
    I personally dislike (hate) the term 'action' that people so often use when talking about monads. It makes it sound like some functions (yes, functions) are not functions, but are actions instead. An action is just a labelling that people (not the language) impose on functions. It's like calling my `int boolVal` a boolean. Not it's not. It's an `int`. You are just using it as a boolean. All in all, everything in Haskell (well maybe not everything... *cough* unsafePerformIO and friends) is a function in the real mathematical sense of the term. – Thomas Eding Sep 01 '11 at 23:08
  • 6
    @trinithis Well, maybe I should have made it clearer that actions are also functions (just like all values in e.g. Haskell are functions, at least if you call constants nullary functions), but _not all functions are actions_. But I don't think the term _action_ is misleading or imprecise. An action is a type of value which you can distinguish by its type, just like you can distinguish `Int`s by their type. I didn't drill too much into the type argument, partly because it's covered in other replies, partly because I wanted to focus on my point. – dainichi Sep 02 '11 at 00:17
  • @Nawaz: (self-promotion) You can check my answer [here](http://stackoverflow.com/questions/3117583/) on actions. It applies to IO, random numbers, time and so on. – sdcvvc Sep 02 '11 at 00:37
  • 38
    Not everything in Haskell is a function - that's utter nonsense. A function is something whose type contains a `->` - that's how the standard defines the term and that's really the only sensible definition in the context of Haskell. So something whose type is `IO Whatever` is **not** a function. – sepp2k Sep 02 '11 at 10:08
  • 7
    @sepp2k: Maybe I am stretching the definition a bit, hence my comments in parentheses. But I am not the first one to come up with the notion of nullary functions, so don't judge me to harshly. Also, what about values whose types contain `=>`? Maybe you (or the standard) don't consider them functions either unless they contain a `->` as well, but I don't feel like I necessarily have to talk about Haskell in the way that you and the standard do, as long as I explain my terminology. – dainichi Sep 02 '11 at 13:42
  • @sepp2k: What about `main :: IO ()` and what about `pi :: Floating` ? – u0b34a0f6ae Sep 05 '11 at 19:08
  • 11
    @sepp2k So, myList :: [a -> b] is a function? ;) – fuz Sep 10 '11 at 15:33
  • 2
    @dainichi The `=>` is used for adding constraints: for example, if you created a generic sorting function, you'd put `Ord a =>` before your type to make sure everything passed in had a method to compare values. It has nothing to do with function types. – Lambda Fairy Jan 06 '12 at 05:17
  • 2
    @Nawaz: That's the point of being able to compose "action"s. You *can*, in principle, translate any imperative program into monadic Haskell code. The difference is that Haskell's type checker enforces the separation of IO operations from purely functional code. – Mechanical snail May 28 '12 at 04:47
  • 4
    @trinithis: Not everything in Haskell is a function! Just like a normal programming language it has things like numbers and strings, say, which are not functions and cannot be applied to arguments. Haskell is a lot less weird than most people seem to think. – Omar Antolín-Camarena Jun 13 '12 at 17:57
  • 3
    @Omar: Perhaps "isomorphic to a function" would be a better phrase then. I was more or less getting at referential transparency. – Thomas Eding Jun 13 '12 at 18:09
  • 2
    While I was okay with the answer "impure stuff happens in a monad", this made it click for me. Also helped me understand why `>>=` is necessary – Raekye Aug 09 '13 at 23:18
  • 10
    @ThomasEding I'm really late to the party, but I just want to clarify this: `putStrLn` is not an action – it is a function that *returns* an action. `getLine` is a variable that *contains* an action. Actions are the values, variables and functions are the "containers"/"labels" we give those actions. – kqr Aug 12 '13 at 22:23
  • 1
    I think adding type annotations might help making this answer even better. – Hjulle Nov 29 '13 at 22:58
  • 2
    This is a nice way of explaining what the IO monad does and helped clarify my understanding, thanks :) – shmish111 Oct 22 '14 at 09:42
  • 1
    Disclaimer I'm talking from category theory perspective @sepp2k Int is a type, List[Int] is a type and List[ _ ] is a function of type Int => List[Int]. Thus IO[ _ ] is a function of Wathever => IO[Wathever] – Coo LHibou Dec 22 '17 at 16:43
  • 1
    @OmarAntolín-Camarena : in category theory, everything is associated to an «id» function. Hence Int and String can be manipulated as id_ int : Int => int – Coo LHibou Dec 22 '17 at 16:46
  • @ThomasEding Monad are so complex and maybe understand in so many way that it is risky to state that there is one interpretation. In the context of this question, I feel that this particular intrepretation is really good – Coo LHibou Dec 22 '17 at 16:46
  • 1
    @dainichi : even though I already know how it worked, the simplicity relevance and clarity of your answer was delicious – Coo LHibou Dec 22 '17 at 16:47
  • @CooLHibou In category theory every object has an identity morphism (morphisms need not be functions). It's still true that Haskell has the number 5, which is not a function: it's type is, say, Int, not of the form a->b. There is, of course, id : Int -> Int but I trust you understand that this id function is *different* from the number 5. – Omar Antolín-Camarena Dec 23 '17 at 17:31
  • @OmarAntolín-Camarena, to a category theorist, 5 is an arrow from () to Int, making it a function! – sara Dec 10 '18 at 07:28
  • 2
    @sara Not quite; a category theorist would say that there is an isomorphism between `Int` and `() -> Int`, in that each element of one can be identified with an element of the other. That doesn't mean an element of one *is* an element of the other. – chepner Apr 21 '19 at 16:54
  • 1
    re ["`myList :: [a -> b]`"](https://stackoverflow.com/questions/7267760/how-can-a-time-function-exist-in-functional-programming?rq=1#comment8899082_7273375) of course it is not a function but a list, because its top type constructor is `[]` (the type in prefix form is `myList :: [] ((->) a b)`. Functions are such things that have a type with the *top* type constructor `(->)`. – Will Ness Oct 29 '19 at 16:53
  • 1
    @dainichi Your answer is just how I like to explain programming with effects. A lot of the comments in here get into the same type of philosopher-talk that makes functional programming confusing to newcomers. – Jim Flood Mar 26 '20 at 09:55
148

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.

chamini2
  • 2,820
  • 2
  • 24
  • 37
fuz
  • 88,405
  • 25
  • 200
  • 352
  • 4
    -1: I'm unhappy with the `RealWorld` smoke screen. Yet, the most important thing is how this purported object is passed on in a chain. The missing piece is where it starts, where the source or connection to the real world is -- it starts with the main function which runs in the IO monad. – u0b34a0f6ae Sep 06 '11 at 14:12
  • 2
    @kaizer.se You can think of a global `RealWorld` object that is passed into the program when it starts. – fuz Sep 06 '11 at 14:21
  • 7
    Basically, your `main` function takes a `RealWorld` argument. Only upon execution is it passed in. – Louis Wasserman Jun 13 '12 at 16:26
  • 13
    You see, the reason why they hide the `RealWorld` and only provide puny functions to change it like `putStrLn`, is so some Haskell programmer doesn't change `RealWorld` with one of their programs such that Haskell Curry's address and birth-date is such they become next-door neighbors growing up (this could damage the time-space continuum in such a way to hurt the Haskell programming language.) – PyRulez Jul 22 '14 at 21:58
  • I think the `RealWorld` metaphor doesn't work very well when starting to think about concurrency. When forking an IO action, does that mean that the entire world is copied? If so, how is it joined again? An analogy to an abstract version of Java's `Runnable` might be better (i.e. `Runnable`s which you can never run yourself but only bind to functions to produce new runnables). – Frerich Raabe Jan 12 '16 at 08:12
  • @FrerichRaabe Good question! The `RealWorld` scheme generally breaks apart under concurrency as you get non-determinism, but so would any scheme. I'm not sure how theory models that. – fuz Jan 12 '16 at 08:19
  • 2
    `RealWorld -> (a, RealWorld)` does not break down as metaphor even under concurrency, as long as you keep in mind that the real world might be changed by other parts of the universe outside of your function (or your current process) at all times. So (a) the methaphor does not break down, and (b) every time a value that has `RealWorld` as its type is passed to a function, the function has to be re-evaluated, because the real world *will* have changed in the meantime (which is modeled as @fuz explained, giving back a different 'token value' every time we interact with the real world). – Qqwy May 08 '19 at 19:10
74

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • 2
    This makes it sound as if Haskell and Clean do different things. From what I understand, they do the same, just that Haskell offers a nicer syntax (?) to accomplish this. – Konrad Rudolph Sep 01 '11 at 13:56
  • 27
    @Konrad: They do the same thing in the sense that both use type system features to abstract side effects, but that's about it. Note that it's very well to explain the IO monad in terms of a world type, but the Haskell standard doesn't actually define a world type and it's not actually possible to get a value of type World in Haskell (while it's very possible and indeed necessary in clean). Further Haskell does not have uniqueness typing as a type system feature, so if it did give you access to a World, it could not ensure that you use it in a pure way the way Clean does. – sepp2k Sep 01 '11 at 14:22
53

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

Vlad Patryshev
  • 1,379
  • 1
  • 10
  • 16
22

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.

Craig Gidney
  • 17,763
  • 5
  • 68
  • 136
  • 1
    Interesting, but that `i++` in the for loop isn't referentially transparent ;) – snim2 Jun 13 '12 at 13:35
  • @snim2 I'm not perfect. :P Take solace in the fact that the dirty mutableness doesn't affect the referential transparency of the result. If you pass the same 'lastMeasurement' in twice, you get a stale next measurement and return the same result. – Craig Gidney Jun 13 '12 at 13:41
  • @Strilanc Thanks for this. I think in imperative code, so it's interesting to see functional concepts explained this way. I can then imagine a language where this natural and syntactically cleaner. – WW. Jul 10 '13 at 06:20
  • You could in fact go the monad way in C# as well, thus avoiding the explicit passing of time stamps. You need something like `struct TimeKleisli { private delegate Res(TimeStampedValue); }`. But code with this still wouldn't look as nice as Haskell with `do` syntax. – leftaroundabout Aug 03 '13 at 18:11
  • @leftaroundabout you can sort of pretend that you have a monad in C# by implementing the bind function as a method called `SelectMany`, which enables the query comprehension syntax. You still can't program polymorphically over monads though, so it's all an uphill battle against the weak type system :( – sara Apr 17 '16 at 11:58
  • @snim2 is the referential transparency problem with the loop due to it taking a different amount of time during different executions? – GrumpyRodriguez Oct 30 '21 at 08:21
18

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 observing that state. (Normal induction models constructing state.)

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

  • Kieburtz, Richard B., "Reactive functional programming" (1997). CSETech. Paper 91 (link)
Will Ness
  • 70,110
  • 9
  • 98
  • 181
Jeffrey Aguilera
  • 1,284
  • 11
  • 8
  • 3
    And how is that related to this question? – Nawaz Sep 19 '14 at 02:06
  • 7
    Your question was about modeling time-dependent behavior in a purely functional way, e.g., a function that returns the current system clock. You can either thread something equivalent to an IO monad through all the functions and their dependency tree to get access to that state; or you can model the state by defining the observation rules rather than the constructive rules. This is why modeling complex state _inductively_ in functional programming seems so unnatural, because the hidden state is really a _coinductive_ property. – Jeffrey Aguilera Sep 30 '14 at 21:12
  • Great source! Is there anything more recent? The JS community still seems to be struggling with stream data abstractions. – Dmitri Zaitsev May 07 '18 at 05:53
13

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

Conal
  • 18,517
  • 2
  • 37
  • 40
11

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.

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ankur
  • 33,367
  • 2
  • 46
  • 72
  • 2
    "After all a software which doesn't interact with the outside world isn't any useful other than doing some mathematical computations." As far as I understand, even in this case the input to the computations would be hard-coded in the program, also not very useful. As soon as you want to read input data to your mathematical computation from file or terminal, you need impure code. – Giorgio Sep 01 '11 at 11:49
  • 1
    @Ankur: That is the same exact thing. If the program is interacting with something else than just itself(e.g. the world through they keyboard, so to speak) it's still impure. – identity Sep 01 '11 at 12:11
  • But command line arguments are something that are passed as initial data to your program and not something that the program asked from the environment and also during the life time of the program the argument values will be same no matter how many times you read it – Ankur Sep 01 '11 at 12:17
  • 1
    @Ankur: Yes, I think you are right! Even though it might not be very practical to pass large input data on the command line, this can be a pure way of doing it. – Giorgio Sep 01 '11 at 12:28
  • 2
    Having the "world object" including the number of people living in the world raises the executing computer to a near omniscient level. I think the normal case is that it includes things like how many files are on your HD and what's the home directory of the current user. – ziggystar Sep 01 '11 at 12:42
  • The "world object" was just a pun :) – Ankur Sep 01 '11 at 12:43
  • @Ankur If you pass all of the input data to the main function, then you can remain pure. It's just very inconvenient - you can't even cheat and pass a stream, because reading a stream involves side effects. – Kris Nuttycombe Sep 01 '11 at 15:29
  • 4
    @ziggystar - the "world object" doesn't actually include anything - it is simply a proxy for the changing state of the world outside of the program. Its only purpose is to explicitly mark mutable state in a way that the type system can identify it. – Kris Nuttycombe Sep 01 '11 at 15:29
11

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.

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.

MduSenthil
  • 2,019
  • 3
  • 18
  • 39
7

Your question conflates two related measures of a computer language: functional/imperative and pure/impure.

A functional language defines relationships between inputs and outputs of functions, and an imperative language describes specific operations in a specific order to perform.

A pure language does not create or depend on side effects, and an impure language uses them throughout.

One-hundred percent pure programs are basically useless. They may perform an interesting calculation, but because they cannot have side effects they have no input or output so you would never know what they calculated.

To be useful at all, a program has to be at least a smidge impure. One way to make a pure program useful is to put it inside a thin impure wrapper. Like this untested Haskell program:

-- this is a pure function, written in functional style.
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

-- This is an impure wrapper around the pure function, written in imperative style
-- It depends on inputs and produces outputs.
main = do
    putStrLn "Please enter the input parameter"
    inputStr <- readLine
    putStrLn "Starting time:"
    getCurrentTime >>= print
    let inputInt = read inputStr    -- this line is pure
    let result = fib inputInt       -- this is also pure
    putStrLn "Result:"
    print result
    putStrLn "Ending time:"
    getCurrentTime >>= print
NovaDenizen
  • 5,089
  • 14
  • 28
  • 4
    It would be helpful if you could address the specific issue of getting the time, and explained a little about to what extent we consider `IO` values and results pure. – AndrewC Sep 28 '12 at 10:31
  • In fact, even 100% pure programs heat up the CPU, which is a side-effect. – Jörg W Mittag Nov 26 '14 at 17:13
3

You're broaching a very important subject in functional programming, that is, performing I/O. The way many pure languages go about it is by using embedded domain-specific languages, e.g., a sublanguage whose task it is to encode actions, which can have results.

The Haskell runtime for example expects me to define an action called main that is composed of all actions that make up my program. The runtime then executes this action. Most of the time, in doing so it executes pure code. From time to time the runtime will use the computed data to perform I/O and feeds back data back into pure code.

You might complain that this sounds like cheating, and in a way it is: by defining actions and expecting the runtime to execute them, the programmer can do everything a normal program can do. But Haskell's strong type system creates a strong barrier between pure and "impure" parts of the program: you cannot simply add, say, two seconds to the current CPU time, and print it, you have to define an action that results in the current CPU time, and pass the result on to another action that adds two seconds and prints the result. Writing too much of a program is considered bad style though, because it makes it hard to infer which effects are caused, compared to Haskell types that tell us everything we can know about what a value is.

Example: clock_t c = time(NULL); printf("%d\n", c + 2); in C, vs. main = getCPUTime >>= \c -> print (c + 2*1000*1000*1000*1000) in Haskell. The operator >>= is used to compose actions, passing the result of the first to a function resulting in the second action. This looking quite arcane, Haskell compilers support syntactic sugar that allows us to write the latter code as follows:

type Clock = Integer -- To make it more similar to the C code

-- An action that returns nothing, but might do something
main :: IO ()
main = do
    -- An action that returns an Integer, which we view as CPU Clock values
    c <- getCPUTime :: IO Clock
    -- An action that prints data, but returns nothing
    print (c + 2*1000*1000*1000*1000) :: IO ()

The latter looks quite imperative, doesn't it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MauganRa
  • 494
  • 6
  • 8
1

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.

Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
0

How can a time function exist in functional programming?

Back in 1988, Dave Harrison was facing this very question when defining an early functional language with real-time processing facilities. The solution he chose for Ruth can be found on page 50 of his thesis Functional Real-Time Programming: The Language Ruth And Its Semantics:

A unique clock is automatically supplied to each Ruth process at run-time, to provide real-time information, [...]

So how are these clocks defined? From page 61:

A clock tree is composed of a node holding a non-negative integer denoting the current time and two sub-trees containing the times of future events.

Furthermore:

As the tree is (lazily) evaluated each of the nodes is instantiated with the value of system time at the time at which the node is instantiated, thus giving programs reference to the current time.

Translating that into Haskell:

type Clock = Tree Time
type Time  = Integer -- must be zero or larger

data Tree a = Node { contents :: a,
                     left     :: Tree a,
                     right    :: Tree a }

In addition to accessing the current time (with contents), each Ruth process can provide other clocks (with left and right) for use elsewhere in the program. If a process needs the current time more than once, it must use a new node on each occasion - once instantiated, a node's contents remains constant.

So that's how a time function can exist in a functional language: by always being applied to a unique input value (a tree-of-times in this case) wherever it's called.

atravers
  • 455
  • 4
  • 8
  • This idea is a nice example for why there are so few people middle-of-the-road wrt functional programming. Those with a feel for the theoretical beauty love it, those who recognize the lack of practicality for what they _actually_ need to program hate it. – Lutz Prechelt Oct 07 '22 at 10:28
  • For those who want that practicality, [HasFuse](https://www2.ki.informatik.uni-frankfurt.de/research/diamond/hasfuse/index.html) could be what they're looking for... – atravers Jan 01 '23 at 06:07
0

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.

darw
  • 941
  • 12
  • 15