This is Haskell, but here's a really simple example.
-- As an ordinary function:
foo :: Int -> Bool -> Int
foo n shouldAdd = if shouldAdd then n + 1 else n - 1
-- Exactly the same, but using the Reader monad
foo :: Int -> Reader Bool Int
foo n = do
shouldAdd <- ask
return (if shouldAdd then n + 1 else n - 1)
Here's the same thing, but with a record with one boolean in it: -- Config: a record with one boolean in it,
-- and you access it with a function called `shouldAdd`
data Config = MkConfig { shouldAdd :: Bool }
foo :: Int -> Config -> Int
foo n cfg = if shouldAdd cfg then n + 1 else n - 1
foo :: Int -> Reader Config Int
foo n = do
mustAdd <- asks shouldAdd
return (if mustAdd then n + 1 else n - 1)
It's basically a way to have implicit read-only parameters. You can call a bunch of functions that take a configuration parameter without having to actually pass the configuration as a parameter explicitly. In an object oriented language, you might use classes for this (if not global variables).So everywhere you deal with a value that is of some type `Configured<T>` you can then refer to all the configuration methods you'd expect of you `Configuration` types. In Java you'd say something like `this.getConfigBlah()`, and it would just work.
> I'm taking some parameters and baking them into methods that I will call later.
Yes.
> But does this have anything to do with monads or some monadic version of state?
In languages that have monads: yes!
No, the whole point is that it’s completely dissimilar to that.
> But does this have anything to do with monads or some monadic version of state?
There is no monadic version of state. The State monad is a way of chaining things together (not unlike shell pipes) which is nice in Haskell because it gives access to some of the language syntactic sugar (the do notation). There is nothing particularly special there otherwise.
The key takeaway here is that you can avoid littering your global scope by explicitly passing what’s shared as functions arguments and then remove side effects if you also pass by value.
Yes, it is this simple.
But ... I'm kind of struggling to figure out what "global configuration as a monad" would look like (very much not a Haskell programmer). How would something like this work in practice?