How can a time function exist in functional programming?
Solution 1:
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.
Solution 2:
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.
Solution 3:
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.