Haskell ReaderT Env IO样板

So8*_*res 6 monads haskell monad-transformers

我有以下样板,我经常这样做,并希望消除.它看起来像这样:

type Configured = ReaderT Config

doSomething :: Configured IO Data
doSomething = do
   getMeta <- asks getMetaData
   meta <- liftIO getMeta
Run Code Online (Sandbox Code Playgroud)

我想减少到这样的事情:

doSomething = do
    meta <- find getMetaData
Run Code Online (Sandbox Code Playgroud)

不幸的是,我还没有完全关注monad变形金刚.是什么类型的find?是(Config -> IO Result) -> Result吗?我怎么写呢?

任何提示/解释,以帮助我grok monad变形金刚非常感谢.

谢谢!

ham*_*mar 11

这可以以相当机械的方式完成.让我们从您的原始代码开始:

doSomething = do
    getMeta <- asks getMetaData
    meta <- liftIO getMeta
    ...
Run Code Online (Sandbox Code Playgroud)

使用第三个monad定律,我们可以将我们想要提取的部分移动到它自己的do-block中:

doSomething = do
    meta <- do getMeta <- asks getMetaData
               liftIO getMeta
    ...
Run Code Online (Sandbox Code Playgroud)

接下来,我们可以提取该子表达式并为其命名:

findMetaData = do getMeta <- asks getMetaData
                  liftIO getMeta

doSomething = do
    meta <- findMetaData
    ...
Run Code Online (Sandbox Code Playgroud)

最后,让我们通过用getMetaData参数替换显式引用来概括它:

find something = do x <- asks something
                    liftIO x

doSomething = do
     meta <- find getMetaData
     ...
Run Code Online (Sandbox Code Playgroud)

现在,我们可以在GHCi中加载它并要求它为我们推断出类型:

*Main> :t find 
find :: (MonadReader r m, MonadIO m) => (r -> IO b) -> m b
Run Code Online (Sandbox Code Playgroud)

或者,我们可能希望将其清理一下并删除虚拟名称x:

find something = ask >>= liftIO . something
Run Code Online (Sandbox Code Playgroud)

为此,我使用asksdo-notation 的定义desugaring规则.

  • 更进一步(如Miikka所述)为您提供"find = asks> => liftIO".谢谢!现在有道理. (2认同)