The opposite of referentially transparent is referentially
opaque. A referentially opaque function is a function that may
mean different things and return different results each time, even if
all arguments are the same.
a
function that just prints a fixed text to the screen and always returns
0, is referentially opaque, because you cannot replace the function call
with 0 without changing the meaning of the program.
n fact, a function, which doesn't take any arguments,
isn't even a function in Haskell. It's simply a value. A number of
simple solutions to this problem exist. One is to expect a state value
as an argument and produce a new state value together with a
pseudorandom number:
random :: RandomState -> (Int, RandomState)
We have
seen that we can solve this problem by expecting a state argument. But
what's our state? The state of the terminal?
A general purpose language is almost useless,
if you can't develop user interfaces or read files. We would like to
read keyboard input or print things to the terminal.
We seem to have found a useful solution to our problem. Just pass the
state value around. But there is a problem with this approach.
A very special feature of
Haskell is the concept of generalization. That means, instead of
implementing an idea directly, you rather try to find a more general
idea, which implies your idea as a special case.
However, the traditional programmer never had to face generalization.
At most they faced abstraction,
they are a
very abstract structure, which allows implementing functionality at an
incredibly general level.
Haskell [1] is a purely functional
programming language. Functions written in it are referentially
transparent. Intuitively that means that a function called with
the same arguments always gives the same result.
askell takes another approach. Instead of passing
the world state explicitly, it employs a structure from category theory
called a monad.
They are an abstract
structure, and at first it can be difficult to understand where they are
useful. The two main interpretations of monads are as containers and as
computations.
The ⊥ value is a theoretical construct. It's the result
of a function, which never returns, so you can't observe that value
directly. Examples are functions, which recurse forever or which throw
an exception. In both cases, there is no ordinary returning of a value.
Now that Nothing is a valid result, our function handles
all cases.
You have some computation with a certain type of
result and a certain structure in its result (like allowing no result,
or allowing arbitrarily many results), and you want to pass that
computation's result to another computation.