我有以下样板,我经常做,并想消除。它看起来像这样:
type Configured = ReaderT Config
doSomething :: Configured IO Data
doSomething = do
getMeta <- asks getMetaData
meta <- liftIO getMeta
我想把它减少到这样:
doSomething = do
meta <- find getMetaData
不幸的是,我还没有完全理解monad变形金刚。 find
的类型是什么?是(Config -> IO Result) -> Result
吗?我该怎么写呢?
非常感谢任何帮助我修改monad变形金刚的提示/解释。
谢谢!
答案 0 :(得分:11)
这可以以相当机械的方式完成。让我们从您的原始代码开始:
doSomething = do
getMeta <- asks getMetaData
meta <- liftIO getMeta
...
使用the third monad law,我们可以将我们想要提取的部分移动到自己的do-block中:
doSomething = do
meta <- do getMeta <- asks getMetaData
liftIO getMeta
...
接下来,我们可以提取该子表达式并为其命名:
findMetaData = do getMeta <- asks getMetaData
liftIO getMeta
doSomething = do
meta <- findMetaData
...
最后,让我们通过用参数替换getMetaData
的显式引用来概括它:
find something = do x <- asks something
liftIO x
doSomething = do
meta <- find getMetaData
...
现在,我们可以在GHCi中加载它,并要求它为我们推断出类型:
*Main> :t find
find :: (MonadReader r m, MonadIO m) => (r -> IO b) -> m b
或者,我们可能希望稍微清理它并删除虚拟名称x
:
find something = ask >>= liftIO . something
为此,我使用了the definition of asks
和the desugaring rules for do-notation。