Search code examples
haskellmonad-transformersreader-monad

Any difference between `Reader a (b -> c)` and `b -> Reader a c`?


(Some other mtl monads would bring up the same problem, but let's just use Reader here to exemplify)

Say I need to show something in a human-readable way, with the implementation and behaviour details depending on the user preferences, read from a configuration:

showIt :: Config -> Object -> String

Where the user configuration is merely read and not to be modified, so might as well use Reader to reflect that:

showIt :: Reader Config (Object -> String)

But wait, how is that different from this:

showIt :: Object -> Reader Config String

Though I hardly know Reader, I do have tried both designs and they seem functionally equivalent. I still wonder if there would be a semantic difference in between, that is, when some other Haskellers look at my code, would they interpret a different purpose or meaning if I had used the other design instead? If so, then which usage should be preferred in scenarios like this?


Solution

  • How is Reader Config (Object -> String) different from Object -> Reader Config String?

    The former limits the showIt implementation to read a config only once, and then produce a string conversion function that must work for all objects. The latter allows the implementation to decide what config to read (or rather, whether to read1) depending on the input object.

    Their usage patterns are quite different:

    do
      showAny <- showIt
      let str1 = showAny object1
      let str2 = showAny object2
      return (str1 ++ " " ++ str2)
    

    vs

    do
      let show1 = showIt object1
      let show2 = showIt object2
      str1 <- show1
      str2 <- show2
      return (str1 ++ " " ++ str2)
    

    1: with the Reader monad, there is no much choice - you can only decide whether to read the config or not (or: how often to read it - but it'll be the same every time). With other monads, where reading different bits of the configuration might involve different file system or database accesses etc, the difference will become larger.