Access environment in a function - haskell

In main I can read my config file, and supply it as runReader (somefunc) myEnv just fine. But somefunc doesn't need access to the myEnv the reader supplies, nor do the next couple in the chain. The function that needs something from myEnv is a tiny leaf function.
How do I get access to the environment in a function without tagging all the intervening functions as (Reader Env)? That can't be right because otherwise you'd just pass myEnv around in the first place. And passing unused parameters through multiple levels of functions is just ugly (isn't it?).
There are plenty of examples I can find on the net but they all seem to have only one level between runReader and accessing the environment.
I'm accepting Chris Taylor's because it's the most thorough and I can see it being useful to others. Thanks too to Heatsink who was the only one who attempted to actually directly answer my question.
For the test app in question I'll probably just ditch the Reader altogether and pass the environment around. It doesn't buy me anything.
I must say I'm still puzzled by the idea that providing static data to function h changes not only its type signature but also those of g which calls it and f which calls g. All this even though the actual types and computations involved are unchanged. It seems like implementation details are leaking all over the code for no real benefit.

You do give everything the return type of Reader Env a, although this isn't as bad as you think. The reason that everything needs this tag is that if f depends on the environment:
type Env = Int
f :: Int -> Reader Int Int
f x = do
env <- ask
return (x + env)
and g calls f:
g x = do
y <- f x
return (x + y)
then g also depends on the environment - the value bound in the line y <- f x can be different, depending on what environment is passed in, so the appropriate type for g is
g :: Int -> Reader Int Int
This is actually a good thing! The type system is forcing you to explicitly recognise the places where your functions depend on the global environment. You can save yourself some typing pain by defining a shortcut for the phrase Reader Int:
type Global = Reader Int
so that now your type annotations are:
f, g :: Int -> Global Int
which is a little more readable.
The alternative to this is to explicitly pass the environment around to all of your functions:
f :: Env -> Int -> Int
f env x = x + env
g :: Env -> Int -> Int
g x = x + (f env x)
This can work, and in fact syntax-wise it's not any worse than using the Reader monad. The difficulty comes when you want to extend the semantics. Say you also depend on having an updatable state of type Int which counts function applications. Now you have to change your functions to:
type Counter = Int
f :: Env -> Counter -> Int -> (Int, Counter)
f env counter x = (x + env, counter + 1)
g :: Env -> Counter -> Int -> (Int, Counter)
g env counter x = let (y, newcounter) = f env counter x
in (x + y, newcounter + 1)
which is decidedly less pleasant. On the other hand, if we are taking the monadic approach, we simply redefine
type Global = ReaderT Env (State Counter)
The old definitions of f and g continue to work without any trouble. To update them to have application-counting semantics, we simply change them to
f :: Int -> Global Int
f x = do
modify (+1)
env <- ask
return (x + env)
g :: Int -> Global Int
g x = do
modify(+1)
y <- f x
return (x + y)
and they now work perfectly. Compare the two methods:
Explicitly passing the environment and state required a complete rewrite when we wanted to add new functionality to our program.
Using a monadic interface required a change of three lines - and the program continued to work even after we had changed the first line, meaning that we could do the refactoring incrementally (and test it after each change) which reduces the likelihood that the refactor introduces new bugs.

Nope. You totally do tag all the intervening functions as Reader Env, or at least as running in some monad with an Env environment. And it totally does get passed around everywhere. That's perfectly normal -- albeit not as inefficient as you might think, and the compiler will often optimize such things away in many places.
Basically, anything that uses the Reader monad -- even if it's very far down -- should be a Reader itself. (If something doesn't use the Reader monad, and doesn't call anything else that does, it doesn't have to be a Reader.)
That said, using the Reader monad means that you don't have to pass the environment around explicitly -- it's handled automatically by the monad.
(Remember, it's just a pointer to the environment getting passed around, not the environment itself, so it's quite cheap.)

Another technique which might be useful is to pass the leaf function itself, partially applied with the value from the config file. Of course this only makes sense if being able to replace the leaf function is somehow to your advantage.

These are truly global variables, since they are initialized exactly once in main. For this situation, it's appropriate to use global variables. You have to use unsafePerformIO to write them if IO is required.
If you're only reading a configuration file, it's pretty easy:
config :: Config
{-# NOINLINE config #-}
config = unsafePerformIO readConfigurationFile
If there are some dependences on other code, so that you have to control when the configuration file is loaded, it's more complicated:
globalConfig :: MVar Config
{-# NOINLINE globalConfig #-}
globalConfig = unsafePerformIO newEmptyMVar
-- Call this from 'main'
initializeGlobalConfig :: Config -> IO ()
initializeGlobalConfig x = putMVar globalConfig x
config :: Config
config = unsafePerformIO $ do
when (isEmptyMVar globalConfig) $ fail "Configuration has not been loaded"
readMVar globalConfig
See also:
Proper way to treat global flags in Haskell
Global variables via unsafePerformIO in Haskell

If you don't want to make everything down to the tiny leaf function be in the Reader monad, does your data allow you to extract the necessary item(s) out of the Reader monad at the top level, and then pass them as ordinary parameters down through to the leaf function? That would eliminate the need for everything in between to be in Reader, although if the leaf function does need to know that it's inside Reader in order to use Reader's facilities then you can't get away from having to run it inside your Reader instance.

Related

Modeling a domain as a GADT type and providing do-sugar for it

Assume we'd like to build a type that represents operations typical for, let's say, a lock-free algorithm:
newtype IntPtr = IntPtr { ptr :: Int } deriving (Eq, Ord, Show)
data Op r where
OpRead :: IntPtr -> Op Int
OpWrite :: IntPtr -> Int -> Op ()
OpCAS :: IntPtr -> Int -> Int -> Op Bool
Ideally, we'd like to represent some algorithms within this model using a convenient do-notation, like (assuming corresponding read = OpRead and cas = OpCAS for aesthetic reasons) the following almost literal translation of the Wikipedia example:
import Prelude hiding (read)
import Control.Monad.Loops
add :: IntPtr -> Int -> Op Int
add p a = snd <$> do
iterateUntil fst $ do
value <- read p
success <- cas p value (value + a)
pure (success, value + a)
How could we achieve that? Let's add a couple more constructors to Op to represent pure injected values and the monadic bind:
OpPure :: a -> Op a
OpBind :: Op a -> (a -> Op b) -> Op b
So let's try to write a Functor instance. OpPure and OpBind is easy, being, for instance:
instance Functor Op where
fmap f (OpPure x) = OpPure (f x)
But the constructors that specify the GADT type start smelling bad:
fmap f (OpRead ptr) = do
val <- OpRead ptr
pure $ f val
Here we assume we'll write the Monad instance later on anyway to avoid ugly nested OpBinds.
Is this the right way to handle such types, or is my design just terribly wrong, this being a sign of it?
This style of using do-notation to build a syntax tree that'll be interpreted later is modelled by the free monad. (I'm actually going to demonstrate what's known as the freer or operational monad, because it's closer to what you have so far.)
Your original Op datatype - without OpPure and OpBind - represents a set of atomic typed instructions (namely read, write and cas). In an imperative language a program is basically a list of instructions, so let's design a datatype which represents a list of Ops.
One idea might be to use an actual list, ie type Program r = [Op r]. Clearly that won't do as it constrains every instruction in the program to have the same return type, which would not make for a very useful programming language.
The key insight is that in any reasonable operational semantics of an interpreted imperative language, control flow doesn't proceed past an instruction until the interpreter has computed a return value for that instruction. That is, the nth instruction of a program depends in general on the results of instructions 0 to n-1. We can model this using continuation passing style.
data Program a where
Return :: a -> Program a
Step :: Op r -> (r -> Program a) -> Program a
A Program is a kind of list of instructions: it's either an empty program which returns a single value, or it's a single instruction followed by a list of instructions. The function inside the Step constructor means that the interpreter running the Program has to come up with an r value before it can resume interpreting the rest of the program. So sequentiality is ensured by the type.
To build your atomic programs read, write and cas, you need to put them in a singleton list. This involves putting the relevant instruction in the Step constructor, and passing a no-op continuation.
lift :: Op a -> Program a
lift i = Step i Return
read ptr = lift (OpRead ptr)
write ptr val = lift (OpWrite ptr val)
cas ptr cmp val = lift (OpCas ptr cmp val)
Program differs from your tweaked Op in that at each Step there's only ever one instruction. OpBind's left argument was potentially a whole tree of Ops. This would've allowed you to distinguish differently-associated >>=s, breaking the monad associativity law.
You can make Program a monad.
instance Monad Program where
return = Return
Return x >>= f = f x
Step i k >>= f = Step i ((>>= f) . k)
>>= basically performs list concatenation - it walks to the end of the list (by composing recursive calls to itself under the Step continuations) and grafts on a new tail. This makes sense - it corresponds to the intutitive "run this program, then run that program" semantics of >>=.
Noting that Program's Monad instance doesn't depend on Op, an obvious generalisation is to parameterise the type of instruction and make Program into a list of any old instruction set.
data Program i a where
Return :: a -> Program i a
Step :: i r -> (r -> Program i a) -> Program a
instance Monad (Program i) where
-- implementation is exactly the same
So Program i is a monad for free, no matter what i is. This version of Program is a rather general tool for modelling imperative languages.

defining functions with/without lambdas

Which difference in does it make if I define a function with a lambda expression or without so when compiling the module with GHC
f :: A -> B
f = \x -> ...
vs.
f :: A -> B
f x = ...
I think I saw that it helps the compiler to inline the function but other than that can it have an impact on my code if I change from the first to the second version.
I am trying to understand someone else's code and get behind the reasoning why this function is defined in the first and not the second way.
To answer that question, I wrote a little program with both ways, and looked at the Core generated:
f1 :: Int -> Int
f1 = \x -> x + 2
{-# NOINLINE f1 #-}
f2 :: Int -> Int
f2 x = x + 2
{-# NOINLINE f2 #-}
I get the core by running ghc test.hs -ddump-simpl. The relevant part is:
f1_rjG :: Int -> Int
[GblId, Arity=1, Str=DmdType]
f1_rjG =
\ (x_alH :: Int) -> + # Int GHC.Num.$fNumInt x_alH (GHC.Types.I# 2)
f2_rlx :: Int -> Int
[GblId, Arity=1, Str=DmdType]
f2_rlx =
\ (x_amG :: Int) -> + # Int GHC.Num.$fNumInt x_amG (GHC.Types.I# 2)
The results are identical, so to answer your question: there is no impact from changing from one form to the other.
That being said, I recommend looking at leftaroundabout's answer, which deals about the cases where there actually is a difference.
First off, the second form is just more flexible (it allows you to do pattern matching, with other clauses below for alternative cases).
When there's only one clause, it's actually equivalent to a lambda... unless you have a where scope. Namely,
f = \x -> someCalculation x y
where y = expensiveConstCalculation
is more efficient than
f x = someCalculation x y
where y = expensiveConstCalculation
because in the latter, y is always recalculated when you evaluate f with a different argument. In the lambda form, y is re-used:
If the signature of f is monomorphic, then f is a constant applicative form, i.e. global constant. That means y is shared throughout your entire program, and only someCalculation needs to be re-done for each call of f. This is typically ideal performance-wise, though of course it also means that y keeps occupying memory.
If f s polymorphic, then it is in fact implicitly a function of the types you're using it with. That means you don't get global sharing, but if you write e.g. map f longList, then still y needs to be computed only once before getting mapped over the list.
That's the gist of the performance differences. Now, of course GHC can rearrange stuff and since it's guaranteed that the results are the same, it might always transform one form to the other if deemed more efficient. But normally it doesn't.

Moving from static configuration to dynamic configuration

I am working on a haskell project where the settings are currently in a file called Setting.hs, so they are checked during compile time and can be accessed globally.
However, since that is a bit too static, I was considering to read the configuration during runtime. The codebase is huge and it seems it would be considerable effort to pass the setting e.g. as an argument through the whole program flow, since they may be arbitrarily accessed from anywhere.
Are there any design patterns, libraries or even ghc extensions that can help here without refactoring the whole code?
Thanks for the hints! I came up with a minimal example which shows how I will go about it with the reflection package:
{-# LANGUAGE Rank2Types, FlexibleContexts, UndecidableInstances #-}
import Data.Reflection
data GlobalConfig = MkGlobalConfig {
getVal1 :: Int
, getVal2 :: Double
, getVal3 :: String
}
main :: IO ()
main = do
let config = MkGlobalConfig 1 2.0 "test"
-- initialize the program flow via 'give'
print $ give config (doSomething 2)
-- this works too, the type is properly inferred
print $ give config (3 + 3)
-- and this as well
print $ give config (addInt 7 3)
-- We need the Given constraint, because we call 'somethingElse', which finally
-- calls 'given' to retrieve the configuration. So it has to be propagated up
-- the program flow.
doSomething :: (Given GlobalConfig) => Int -> Int
doSomething = somethingElse "abc"
-- since we call 'given' inside the function to retrieve the configuration,
-- we need the Given constraint
somethingElse :: (Given GlobalConfig) => String -> Int -> Int
somethingElse str x
| str == "something" = x + getVal1 given
| getVal3 given == "test" = 0 + getVal1 given
| otherwise = round (fromIntegral x * getVal2 given)
-- no need for Given constraint here, since this does not use 'given'
-- or any other functions that would
addInt :: Int -> Int -> Int
addInt = (+)
The Given class is a bit easier to work with and perfectly suitable for a global configuration model. All functions that do not make use of given (which gets the value) don't seem to need the class constraint. That means I only have to change functions that actually access the global configuration.
That's what I was looking for.
What you are asking, if it was possible would break referential transparency, at least for pure function ( a pure function result can depend on some global variables but not on a config file couldn't it ) ?
Usually people avoid that type of situation by passing implicitly the configuration as data via a Monad. Alternatively (if you are happy to refactor your code a bit) you can use the implicit parameter extenson, which in theory has been made to solve that type of problem but in practice doesn't really work.
However, if you really need, you can use unsafePerformIO and ioRef to have a top level mutable state which is dirty and frowned upton. You need a top level mutable state, because you need to be able to modify "mutate" your initial config when you are loading it.
Then you get things like that :
myGlobalVar :: IORef Int
{-# NOINLINE myGlobalVar #-}
myGlobalVar = unsafePerformIO (newIORef 17)

Using parameters that don't change after being read

I'm learning Haskell and writing a program to solve a toy problem. The program uses a parameter k that doesn't change while it is running, after the parameter has been read from a file. I'm very new to using pure functions, and I would like to write as many functions as pure ones as I can.
I have a data type Node, and functions to compare nodes, get the descendants of nodes, and more. Currently, all of these functions take a parameter k as an argument, such as
compare k node1 node2 = ...
desc k node = ...
and whenever I have to recursively call any of these within the function, I have to repeat the k parameter. It seems redundant, since k will never have a different value for these functions and since it makes the type signatures less readable, and I would like to refactor it out if possible.
Are there any strategies to do this with pure functions, or is it simply a limitation I'll have to deal with?
What I've thought of
Earlier I hard-coded k at the top level, and it seemed to work (I was able to use k in the functions without needing it as an explicit argument). But this obviously wasn't feasible once I needed to read input from file.
Another possible strategy would be to define all these functions in the main function, but this seems to be strongly discouraged in Haskell.
The usual Haskell approach would be to use the Reader monad. One way of thinking about Reader is that it provides computations with access to an environment. It can be defined as
newtype Reader r a = Reader { runReader :: r -> a }
So your functions would have the types
compare :: Node -> Node -> Reader k Ordering -- or Bool, or whatever the return value is
desc :: Node -> Reader k String -- again, guessing at the output type.
Within a Reader computation, use the function ask :: Reader r r to get access to the parameter.
At the top level, you can run a Reader computation with runReader theComputation env
This is often nicer than passing arguments explicitly. First, any function that doesn't need the environment can be written as a normal function without taking it as a parameter. If it calls another function that does use the environment, the monad will provide it automatically with no extra work on your part.
You can even define a type synonym,
type MyEnv = Reader Env
and use that for your functions type signatures. Then if you need to change the environment, you only need to change one type instead of changing all your type signatures.
The definition from standard libraries is a bit more complicated to handle monad transformers, but it works the same way as this simpler version.
Ultimately you have to pass in the value of k everywhere it is needed, but there are some things you can do to avoid repeating it.
One thing you can do is to define convenience functions once the value of k is known:
myfunc = let k = ...
compare' = compare k
desc' = desc k
in ...
(use compare' and desc' here)
Another approach is to use the Implicit Parameters extension. This involves defining compare and desc to take k as an implicit parameter:
{-# LANGUAGE ImplicitParameters #-}
compare :: (?k :: Int) => Node -> Node
compare n1 n2 = ... (can use ?k here) ...
desc :: (?k :: Int) => Node
desc = ... (can use ?k here) ...
myfunc = let ?k = ...
in ... use compare and desc ...
Note that in either case you can't call compare or desc until you've defined what k is.
This is how I like to structure recursive functions with values that don't change
map f xs = map' xs
where map' (x:xs) = f x : map' xs
Two simple tricks with local function definitions that may be useful. First, you can make k implicit within your recursive definitions by just playing with scope:
desc :: Int -> Node -> [Node]
desc k node = desc' node
where
desc' node = -- Carry on; k is in scope now.
Second, if you are going to call your functions a lot of times with the same k within the same scope, you can use a local definition for the partially applied function:
main = do
k <- getKFromFile
-- etc.
let desc' = desc k -- Partial application.
descA = desc' nodeA
descB = desc' nodeB
print [descA, descB]
Proper implicit parameter passing is commonly done (or, arguably, simulated) with the Reader monad (see John L's answer), though that sounds kind of heavyweight for your use case.

What is the purpose of the reader monad?

The reader monad is so complex and seems to be useless. In an imperative language like Java or C++, there is no equivalent concept for the reader monad, if I am not mistaken.
Can you give me a simple example and clear this up a little bit?
Don't be scared! The reader monad is actually not so complicated, and has real easy-to-use utility.
There are two ways of approaching a monad: we can ask
What does the monad do? What operations is it equipped with? What is it good for?
How is the monad implemented? From where does it arise?
From the first approach, the reader monad is some abstract type
data Reader env a
such that
-- Reader is a monad
instance Monad (Reader env)
-- and we have a function to get its environment
ask :: Reader env env
-- finally, we can run a Reader
runReader :: Reader env a -> env -> a
So how do we use this? Well, the reader monad is good for passing (implicit) configuration information through a computation.
Any time you have a "constant" in a computation that you need at various points, but really you would like to be able to perform the same computation with different values, then you should use a reader monad.
Reader monads are also used to do what the OO people call dependency injection. For example, the negamax algorithm is used frequently (in highly optimized forms) to compute the value of a position in a two player game. The algorithm itself though does not care what game you are playing, except that you need to be able to determine what the "next" positions are in the game, and you need to be able to tell if the current position is a victory position.
import Control.Monad.Reader
data GameState = NotOver | FirstPlayerWin | SecondPlayerWin | Tie
data Game position
= Game {
getNext :: position -> [position],
getState :: position -> GameState
}
getNext' :: position -> Reader (Game position) [position]
getNext' position
= do game <- ask
return $ getNext game position
getState' :: position -> Reader (Game position) GameState
getState' position
= do game <- ask
return $ getState game position
negamax :: Double -> position -> Reader (Game position) Double
negamax color position
= do state <- getState' position
case state of
FirstPlayerWin -> return color
SecondPlayerWin -> return $ negate color
Tie -> return 0
NotOver -> do possible <- getNext' position
values <- mapM ((liftM negate) . negamax (negate color)) possible
return $ maximum values
This will then work with any finite, deterministic, two player game.
This pattern is useful even for things that are not really dependency injection. Suppose you work in finance, you might design some complicated logic for pricing an asset (a derivative say), which is all well and good and you can do without any stinking monads. But then, you modify your program to deal with multiple currencies. You need to be able to convert between currencies on the fly. Your first attempt is to define a top level function
type CurrencyDict = Map CurrencyName Dollars
currencyDict :: CurrencyDict
to get spot prices. You can then call this dictionary in your code....but wait! That won't work! The currency dictionary is immutable and so has to be the same not only for the life of your program, but from the time it gets compiled! So what do you do? Well, one option would be to use the Reader monad:
computePrice :: Reader CurrencyDict Dollars
computePrice
= do currencyDict <- ask
--insert computation here
Perhaps the most classic use-case is in implementing interpreters. But, before we look at that, we need to introduce another function
local :: (env -> env) -> Reader env a -> Reader env a
Okay, so Haskell and other functional languages are based on the lambda calculus. Lambda calculus has a syntax that looks like
data Term = Apply Term Term | Lambda String Term | Var Term deriving (Show)
and we want to write an evaluator for this language. To do so, we will need to keep track of an environment, which is a list of bindings associated with terms (actually it will be closures because we want to do static scoping).
newtype Env = Env ([(String, Closure)])
type Closure = (Term, Env)
When we are done, we should get out a value (or an error):
data Value = Lam String Closure | Failure String
So, let's write the interpreter:
interp' :: Term -> Reader Env Value
--when we have a lambda term, we can just return it
interp' (Lambda nv t)
= do env <- ask
return $ Lam nv (t, env)
--when we run into a value, we look it up in the environment
interp' (Var v)
= do (Env env) <- ask
case lookup (show v) env of
-- if it is not in the environment we have a problem
Nothing -> return . Failure $ "unbound variable: " ++ (show v)
-- if it is in the environment, then we should interpret it
Just (term, env) -> local (const env) $ interp' term
--the complicated case is an application
interp' (Apply t1 t2)
= do v1 <- interp' t1
case v1 of
Failure s -> return (Failure s)
Lam nv clos -> local (\(Env ls) -> Env ((nv, clos) : ls)) $ interp' t2
--I guess not that complicated!
Finally, we can use it by passing a trivial environment:
interp :: Term -> Value
interp term = runReader (interp' term) (Env [])
And that is it. A fully functional interpreter for the lambda calculus.
The other way to think about this is to ask: How is it implemented? The answer is that the reader monad is actually one of the simplest and most elegant of all monads.
newtype Reader env a = Reader {runReader :: env -> a}
Reader is just a fancy name for functions! We have already defined runReader so what about the other parts of the API? Well, every Monad is also a Functor:
instance Functor (Reader env) where
fmap f (Reader g) = Reader $ f . g
Now, to get a monad:
instance Monad (Reader env) where
return x = Reader (\_ -> x)
(Reader f) >>= g = Reader $ \x -> runReader (g (f x)) x
which is not so scary. ask is really simple:
ask = Reader $ \x -> x
while local isn't so bad:
local f (Reader g) = Reader $ \x -> runReader g (f x)
Okay, so the reader monad is just a function. Why have Reader at all? Good question. Actually, you don't need it!
instance Functor ((->) env) where
fmap = (.)
instance Monad ((->) env) where
return = const
f >>= g = \x -> g (f x) x
These are even simpler. What's more, ask is just id and local is just function composition with the order of the functions switched!
I remember being puzzled as you were, until I discovered on my own that variants of the Reader monad are everywhere. How did I discover it? Because I kept writing code that turned out to be small variations on it.
For example, at one point I was writing some code to deal with historical values; values that change over time. A very simple model of this is functions from points of time to the value at that point in time:
import Control.Applicative
-- | A History with timeline type t and value type a.
newtype History t a = History { observe :: t -> a }
instance Functor (History t) where
-- Apply a function to the contents of a historical value
fmap f hist = History (f . observe hist)
instance Applicative (History t) where
-- A "pure" History is one that has the same value at all points in time
pure = History . const
-- This applies a function that changes over time to a value that also
-- changes, by observing both at the same point in time.
ff <*> fx = History $ \t -> (observe ff t) (observe fx t)
instance Monad (History t) where
return = pure
ma >>= f = History $ \t -> observe (f (observe ma t)) t
The Applicative instance means that if you have employees :: History Day [Person] and customers :: History Day [Person] you can do this:
-- | For any given day, the list of employees followed by the customers
employeesAndCustomers :: History Day [Person]
employeesAndCustomers = (++) <$> employees <*> customers
I.e., Functor and Applicative allow us to adapt regular, non-historical functions to work with histories.
The monad instance is most intuitively understood by considering the function (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c. A function of type a -> History t b is a function that maps an a to a history of b values; for example, you could have getSupervisor :: Person -> History Day Supervisor, and getVP :: Supervisor -> History Day VP. So the Monad instance for History is about composing functions like these; for example, getSupervisor >=> getVP :: Person -> History Day VP is the function that gets, for any Person, the history of VPs that they've had.
Well, this History monad is actually exactly the same as Reader. History t a is really the same as Reader t a (which is the same as t -> a).
Another example: I've been prototyping OLAP designs in Haskell recently. One idea here is that of a "hypercube," which is a mapping from intersections of a set of dimensions to values. Here we go again:
newtype Hypercube intersection value = Hypercube { get :: intersection -> value }
One common of operation on hypercubes is to apply a multi-place scalar functions to corresponding points of a hypercube. This we can get by defining an Applicative instance for Hypercube:
instance Functor (Hypercube intersection) where
fmap f cube = Hypercube (f . get cube)
instance Applicative (Hypercube intersection) where
-- A "pure" Hypercube is one that has the same value at all intersections
pure = Hypercube . const
-- Apply each function in the #ff# hypercube to its corresponding point
-- in #fx#.
ff <*> fx = Hypercube $ \x -> (get ff x) (get fx x)
I just copypasted the History code above and changed names. As you can tell, Hypercube is also just Reader.
It goes on and on. For example, language interpreters also boil down to Reader, when you apply this model:
Expression = a Reader
Free variables = uses of ask
Evaluation environment = Reader execution environment.
Binding constructs = local
A good analogy is that a Reader r a represents an a with "holes" in it, that prevent you from knowing which a we're talking about. You can only get an actual a once you supply a an r to fill in the holes. There are tons of things like that. In the examples above, a "history" is a value that can't be computed until you specify a time, a hypercube is a value that can't be computed until you specify an intersection, and a language expression is a value that can't be computed until you supply the values of the variables. It also gives you an intuition on why Reader r a is the same as r -> a, because such a function is also intuitively an a missing an r.
So the Functor, Applicative and Monad instances of Reader are a very useful generalization for cases where you are modeling anything of the sort "an a that's missing an r," and allow you to treat these "incomplete" objects as if they were complete.
Yet another way of saying the same thing: a Reader r a is something that consumes r and produces a, and the Functor, Applicative and Monad instances are basic patterns for working with Readers. Functor = make a Reader that modifies the output of another Reader; Applicative = connect two Readers to the same input and combine their outputs; Monad = inspect the result of a Reader and use it to construct another Reader. The local and withReader functions = make a Reader that modifies the input to another Reader.
In Java or C++ you may access any variable from anywhere without any problem. Problems appears when your code becomes multi-threaded.
In Haskell you have only two ways to pass the value from one function to another:
You pass the value through one of input parameters of the callable function. Drawbacks are: 1) you can't pass ALL the variables in that way - list of input parameters just blow your mind. 2) in sequence of function calls: fn1 -> fn2 -> fn3, function fn2 may not need parameter which you pass from fn1 to fn3.
You pass the value in scope of some monad. Drawback is: you have to get firm understanding what Monad conception is. Passing the values around is just one of great deal of applications where you may use the Monads. Actually Monad conception is incredible powerful. Don't be upset, if you didn't get insight at once. Just keep trying, and read different tutorials. The knowledge you'll get will pay off.
The Reader monad just pass the data you want to share between functions. Functions may read that data, but can't change it. That's all that do the Reader monad. Well, almost all. There are also number of functions like local, but for the first time you can stick with asks only.

Resources