gpt4 book ai didi

haskell - 如何使用非 IO "exterior"构建 Monad,但 IO "interior"?

转载 作者:行者123 更新时间:2023-12-04 01:21:09 24 4
gpt4 key购买 nike

我正在尝试编写一个呈现一些 HTML 的 Monad,同时跟踪(和缓存)一些特定的函数调用。这是我尝试过的:

data TemplateM a = TemplateM
{ templateCache :: ![(Text, Text)]
, templateResult :: !(IO a)
}

下面是我打算如何使用它:

renderCached :: Text -> TemplateM Text
renderCached k =
-- lookup templateCache from the monadic context, if it lacks the key,
-- then fetch the key from an external data source (which is where the
-- "IO interior" comes from, and store it in templateCache (monadic context)

值得注意的是,我不希望通过 liftTemplateM 中执行任意 IO 操作,liftIO 等。 TemplateM 中应该发生的唯一 IO 是通过 renderCached 函数从缓存中获取一些内容。

我能够为此定义 FunctorApplicative 实例,但完全无法使用 Monad 实例。这是我得到的结果:

instance Functor TemplateM where
{-# INLINE fmap #-}
fmap fn tmpl = tmpl{templateResult=fmap fn (templateResult tmpl)}

instance Applicative TemplateM where
{-# INLINE pure #-}
pure x = TemplateM
{ templateCache = []
, templateResult = pure x
}

{-# INLINE (<*>) #-}
fn <*> f =
let fnCache = templateCache fn
fnFunction = templateResult fn
fCache = templateCache f
fResult = templateResult f
in TemplateM { templateCache = fnCache <> fCache
, templateResult = fnFunction <*> fResult
}

有没有什么方法可以为此编写 Monad 实例而不将 IO 内部结构暴露给外界?

最佳答案

我已经在 ReaderT 之上制定了一个解决方案,但我真的想让我最初的想法发挥作用:

newtype TemplateM a = TemplateM { unTemplateM :: ReaderT (IORef [(Text, Text)]) IO a } deriving (Functor, Applicative, Monad)

renderCached :: Text -> TemplateM Text
renderCached k = TemplateM $ do
-- this is just dummy code. The actual cache lookup has not
-- been implemented, but the types align
v <- pure $ "rendered template for " <> k
cacheRef <- ask
atomicModifyIORef' cacheRef (\x -> ((k, v):x, ()))
pure v

runTemplateM :: [(Text, Text)]
-> TemplateM a
-> IO ([(Text, Text)], a)
runTemplateM initialCache x = do
initialCacheRef <- newIORef initialCache
(flip runReaderT) initialCacheRef $ do
res <- unTemplateM x
ref <- ask
finalCache <- readIORef ref
pure (finalCache, res)

关于haskell - 如何使用非 IO "exterior"构建 Monad,但 IO "interior"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62631211/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com