1

Is there an equivalent to the Reader monad that's equivalent to a -> b -> c rather than just a -> b. I know I could do (a, b) -> c but I'm not sure that's going to be very ergonomic.

joel
  • 6,359
  • 2
  • 30
  • 55
  • 1
    [shameless self-promotion](https://hackage.haskell.org/package/effect-stack) – Daniel Wagner Apr 03 '22 at 19:07
  • Just in case someone reading this question is writing an app, in that circumstance I would replace `a` in the reader monad with a problem-specific custom type containing all the relevant things I want access to in the main body of my app. Probably a record type. – AndrewC Apr 09 '22 at 23:54

1 Answers1

0

The only way to make that a monad is by wrapping it which may not be what you're after. The instance can be derived

{-# Language DerivingVia #-}

import Control.Monad.Reader

newtype Reader2 a b c = Reader2 (a -> b -> c)
 deriving (Functor, Applicative, Monad, MonadFix, MonadReader a)
 via ReaderT a ((->) b)

If you derive Representable it witnesses the isomorphism between Reader2 a b c and (a, b) -> c

index    :: Reader2 a b c -> ((a, b) -> c)
tabulate :: ((a, b) -> c) -> Reader2 a b c
Iceland_jack
  • 6,848
  • 7
  • 37
  • 46
  • Why not `newtype ReaderT2 e f m a = ReaderT2 { unReaderT2 :: ReaderT e (ReaderT f m) a }`? – dfeuer Apr 03 '22 at 17:30
  • That works great, and then `type Reader2 a b = ReaderT2 a b Identity` but why do you keep the newtypes inside the definition? And there is a new package [*deriving-trans*](https://hackage.haskell.org/package/deriving-trans) that lets you derive the lifting function for monad transformers: ``MonadTrans via ReaderT e `ComposeT` ReaderT f`` – Iceland_jack Apr 03 '22 at 17:40
  • For `ReaderT`, it probably wouldn't make sense, but for more complicated things you may want to maintain abstraction. – dfeuer Apr 03 '22 at 18:33