I'm trying to marry the approach given at http://lexi-lambda.github.io/blog/2016/06/12/four-months-with-haskell/ (section titled "Typeclasses can emulate effects") with some sort of homegrown reader monad.
The overall problem I'm trying to solve is to avoid passing around a configuration variable to almost ever function in my app. And the reason I can't use a ReaderT
is because a lot of my functions are in SqlPersistT
, which itself uses a ReaderT
internally. The other reason is to learn all this mental gymnastics better.
My two questions are given as comments in the code below. Reproducing them here as well:
- What is the most appropriate way to define
NwMonad
? - Consequently, how do define
NwMonad
as an instance ofHasNwConfig
? How to write the function body ofaskNwConfig
? - How do I finally call
runNwMonad
? What will be its arguments?
Here's the code:
data NwConfig = NwConfig {
_googleClientId :: T.Text,
_googleClientSecret :: T.Text,
_tgramBotToken :: String,
_aria2Command :: String,
_aria2DownloadDir :: String
}
$(makeLenses ''NwConfig)
instance Default NwConfig where
def = NwConfig{}
class MonadIO m => HasNwConfig m where
askNwConfig :: m NwConfig
startAria2 :: (HasNwConfig m) => m Sytem.Process.ProcessHandle
cfg <- askNwConfig
(_, _, _, processHandle) <- createProcess $ proc (cfg ^. aria2Command) []
return processHandle
-- QUESTION: Is this correct?
data NwMonad a = NwMonad{runNwMonad :: (NwConfig -> IO a)}
deriving (Functor, Applicative, Monad, MonadIO)
-- Or is this the way to do it?
data NwMonad a = NwMonad{runNwMonad :: IO a, nwConfig :: NwConfig}
deriving (Functor, Applicative, Monad, MonadIO)
instance HasNwConfig NwMonad where
askNwConfig = return . nwConfig -- QUESTION: How to write this?
main :: IO ()
main = do
[cId, cSecret, botToken] <- sequence [getEnv "GOOGLE_CLIENT_ID", getEnv "GOOGLE_CLIENT_SECRET", getEnv "TELEGRAM_TOKEN"]
let cfg = (def :: NwConfig)
& googleClientId .~ (T.pack cId)
& googleClientSecret .~ (T.pack cSecret)
& tgramBotToken .~ botToken
& aria2Command .~ "/Users/saurabhnanda/projects/nightwatch/aria2-1.19.3/bin/aria2c"
-- QUESTION: How do I use this now?
runNwMonad $ (?????) $ startAria2