******************** Chapter 22: Reader ******************** **Hey; Stop!** This chapter sucks, and so do my notes on it. Go read `this simple example `_, instead. 22.1 Reader ----------- .. Paragraph 2. a) When writing applications, programmers often need to pass around some information that may be needed intermittently or universally throughtout an entire application. * Ok, so things like envionment variables, config file directives, the os type, etc. b) We don't want to simply pass this information as arguments, because it would be present in the type of almost every function. * When you say "pass this information as arguments", what do you have in mind? Do you mean passing all of the information as a single argument, such as a named record containing all name:value pairs you may want to access (an environment)? Or do you mean passing each possible config option individually; where each option has a separate argument that functions must accept using appropriate parameters, respectively? Or maybe something else? * Can you show an example of what this would look like? * Why not use another approach like: * A top-level definition; or * a closure (an enclosing scope that contains any names you may wish to access), possibly generated by a function, like the JS function factory pattern, Python decerators; or * an expression imported from a module. c) This can make the code harder to read and harder to maintain. * How does having explicit arguments make the code harder to read? * Wouldn't it be easier to read, since you know what data the functions depend on? * Can you show an example of what you have in mind? .. The Reader monad effectively creates a global read-only value of a specified type. All functions within the monad can "read" the type. ~ https://mmhaskell.com/blog/2017/ 2/20/how-to-read-and-write-with-monads .. The phrase "dependency injection" keeps on coming up. What is that? In this chapter, we will: * examine the ``Functor``, ``Applicative``, and ``Monad`` type class instances for *functions*; * learn about the ``Reader`` newtype; * and see some examples of using ``Reader``. .. First off, what is reader used for? .. ----------------------------------- .. Reader is a monad for querying things from an .. environment. Think of it as a named closure .. that can be generated at runtime and shows up .. in type signatures. .. It provides three operations: .. * ``ask``, which we can use to retrieve a value with. .. * ``local``, which executes a computation .. within the environment that our ``Reader`` .. encapsulates; and .. * ``reader``, which retrieves a ... uhh, I .. don't know what this one does. .. You won't find the ``Reader`` type as defined .. in this book anywhere on Hackage; Instead, the .. ``mtl`` package provides ``ReaderT``, which .. can be used to define it. .. Like this:: .. import Control.Monad.Reader (ReaderT) .. import .. type Reader r = ReaderT r Identity .. :: .. ----------------------------------------------------------- .. -- From the mtl package, in the module Control.Monad.Reader .. ----------------------------------------------------------- .. class Monad m => MonadReader r m | m -> r where .. -- | Retrieves the monad environment. .. ask :: m r .. ask = reader id .. -- | Executes a coputation in a modified environment. .. local :: (r -> r) -- ^ The function to modify the environment. .. -> m a -- ^ Reader to run in the modified environment. .. -> m a .. -- | Retrieves a function of the current environment. .. reader :: (r -> a) -- ^ The selector function to apply to the environment. .. -> m a .. reader f = do .. r <- ask .. return (f r) .. {-# MINIMAL (ask | reader), local #-} .. .. https://gist.github.com/egonSchiele/5752172 22.2 A new beginning -------------------- This section demonstrates how the instances of ``Functor``, ``Applicative``, and ``Monad`` work for functions. Why is this relevant to ``Reader``? Well, ``Reader`` is implemented as a wrapper for the function type constructor, so the behaviour listed here applies to the class methods of ``Reader``. .. The function is represented as ``((->) r)`` in .. the instance definitions, where ``(->)`` is .. the function type constructor, and ``r`` is a .. type variable to it. .. In all cases, the "structure" being operated .. on by the class methods is ``(->)``, and the .. "contained element" is the argument to that .. function on the term level, which is of type .. ``r``. Here is a recording of me following along with the section. .. raw:: html The Functor instance for functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``fmap`` applies functions to each element within a structure. Some of these structures make intuitive sense, like lists. But, did you know you can also ``fmap`` a function over another function? .. :: .. .. ·∾ -- We can fmap a function over another function, like this: .. ·∾ fmap (\x -> (*) x 2) (\y -> (+) y 10) $ 5 .. 30 .. .. ·∾ -- What happens is that (\x -> (*) x 2) is applied to y. .. ·∾ -- [ y := ((\x -> (*) x 2) y) ] .. ·∾ (\y -> (+) ((\x -> (*) x 2) y) 10) 5 .. 20 .. .. ·∾ -- This means that in order for the resulting function to compl .. ete its evaluation, the argument to it must first be passed throug .. h the function that we're mapping. .. .. ·∾ -- Which is really just function composition. So this... .. .. ·∾ (\x -> (*) x 2) . (\y -> (+) y 10) $ 5 .. 30 .. .. ·∾ -- is the same as this... .. .. ·∾ (\x -> (*) x 2) <$> (\y -> (+) y 10) $ 5 .. 30 In the case of ``fmap``'ping a function over a function, what is the containing structure, and what are the elements that we operate on within that structure? Answer: The structure is a partially applied function, and the elements are the arguments to that function. So something like this:: fmap (\x -> (+) 10 x) (\y -> (*) 2 y) Will evaluate to this:: \y -> (*) 2 ((\x -> (+) 10 x) y) As you can see, the function we map gets applied to the argument of our containing function, meaning that the function ``f`` must act on the result of it's argument with ``g`` applied. This is really just function composition. Here's what the definition of ``fmap`` looks like, `taken from GHC.Base `_ at the time of this writing:: instance Functor ((->) r) where fmap = (.) The Applicative instance for functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Let's look at how sequential application works, now:: -- page 846, figure 4 bbop :: Integer -> Integer bbop = (+) <$> boop <*> doop duwop :: Integer -> Integer duwop = liftA2 (+) boop doop Around this area in the book, there are a few remarks explaining how ``liftA2`` is evaluated, but I found them mostly unhelpful. There are also some examples, but I don't understand them. I really tried to; But I don't. .. There are many remarks I didn't understand until I looked up the instance declaration. I'm going to list them here in an attempt to debug my reading process. Paragraph 10 c) This time, the argument gets passed to both ``boop`` and ``doop`` in parallel, and the results are added together. Questions I asked myself: * What does "in parallel" mean? After finding the instance for Applicative below, it became clear. Without that information, I never would have figured it out. Paragraph 13 Mapping a function awaiting two arguments over a function awaiting one produces a two argument function. I also had a hard time following the examples where they desugared the expression: Prelude> bbop 3 In figure 6, and after paragraph 12. Paragraph 21, and figure 13 * I've completely lost track of how he's picking apart the evaluation, here. Why are we defining a new function, appReader? Figure 15: What is this a figure of? What does it do? I get the feeling that the author wants us to derive how (<*>) works from the type signature. Instead, here is the ``Applicative`` instance for functions:: instance Applicative ((->) r) where pure = const (<*>) f g x = f x (g x) liftA2 q f g x = q (f x) (g x) ...and here is a transcript of me mechanically desugaring an expression that uses ``(<*>)`` in GHCi: .. include:: figures/22.2/desugaring_apply.txt :code: The Monad instance for functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This example does the same thing as the last one, but is phrased to use the ``Monad`` instance of ``(->)``, instead of ``Applicative``:: boopDoop :: Integer -> Integer boopDoop = do a <- boop b <- doop return (a + b) Here is the instance definition, so we can decode it:: instance Monad ((->) r) where return = const f >>= k = \r -> k (f r) r ...and here I go, desugaring ``boopDoop``: .. include:: figures/22.2/desugaring_f16.hs :code: .. paragraph 28 a) The Functor of function is function composition. b) The Applicative and Monad chain the argument forward in addition to the composition (applicatives and monads are both varieties of functors, so they retain that core functorial behaviour). * What does "chain the argument forward" mean? .. Paragraph 29 a) This is the idea of Reader. b) It is a way of stringing functions together when all those functions are awaiting one input from a shared environment. c) We're going to get into the details of how it works, but the important intuition here is that it's another way of abstracting out function application, and it gives us a way to do computation in terms of an argument that hasn't been supplied yet. d) We use this most often when we have a constant value that we will obtain from womewhere outside our program that will be an argument to a whole bunch of functions. e) Using Reader allows us to avoid passing that argument around explicitly. .. include:: exercises/22.2.1_-_warming_up.rst 22.3 This is Reader ------------------- Usually when you see the term ``Reader``, it is used to refer to the ``Monad`` instance of the function type constructor. Reader is all about reading an argument from the environment into functions. 22.4 Breaking down the Functor of functions ------------------------------------------- Specialize the ``f`` in ``fmap``'s type signature to the function constructor and you get ``(.)``:: fmap :: Functor f => (a -> b) -> f a -> f b -- [ f := ((->) r) ] fmap :: (a -> b) -> (r -> a) -> (r -> b) -- [ b := c ] fmap :: (a -> c) -> (r -> a) -> (r -> c) -- [ a := b ] fmap :: (b -> c) -> (r -> b) -> (r -> c) -- [ r := a ] fmap :: (b -> c) -> (a -> b) -> (a -> c) (.) :: (b -> c) -> (a -> b) -> (a -> c) 22.5 But uh, Reader? -------------------- .. Other resources to understand Reader .. https://www.mjoldfield.com/atelier/2014/08/monads-reader.html .. https://blog.latukha.com/haskell-notes.html#org7373240 ``Reader`` is a newtype wrapper for the function type:: newtype Reader r a = Reader { runReader :: r -> a } The ``r`` is the type we're reading in, and ``a`` is the result type of our function. .. Wait! Where do I find reader? If you search for ``Reader`` on Hoogle, you won't find an exact match. Instead, the closest match will be ``ReaderT``, which comes from either the ``Control.Monad.Trans`` module of the ``transformers`` package, or the ``Control.Monad.Reader`` module of the ``mtl`` package. The ``Reader`` monad, as it appears in the book, is equivalent to this definition using functions from ``Control.Monad.Reader``:: type Reader r = ReaderT r Identity