我正在尝试将http://lexi-lambda.github.io/blog/2016/06/12/four-months-with-haskell/(标题为“Typeclasses can emulate effects”的部分)与一些方法结合起来有点像本土读者单子。
我要解决的总体问题是避免将配置变量传递给我的应用程序中几乎所有功能。我不能使用 a 的原因ReaderT
是因为我的很多函数都在 in SqlPersistT
,它本身在ReaderT
内部使用 a 。另一个原因是更好地学习所有这些心理体操。
我的两个问题在下面的代码中作为注释给出。在这里也复制它们:
- 最合适的定义方式是
NwMonad
什么? - 因此,如何定义
NwMonad
为HasNwConfig
? 函数体怎么写askNwConfig
? - 我最后怎么打电话
runNwMonad
?它的论点是什么?
这是代码:
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