在 Free monad interpreter使用 iterT
,我想要一个内部状态,但我不知道如何做,因为 iterT
函数提供延续 f
据我所知,预先加载了递归调用。我想一个 StateT
包装器是一个可能的解决方案(?),但如果可能的话最好避免。谢谢。
编辑:澄清一下,内部状态是 mval
传递给 inner
的参数功能我想分配一个资源并继续使用该资源进行解释。
import Control.Monad.Trans.Free.Church
import Control.Monad.Free.TH
type SomeFree m = FT SomeFreeF m
data SomeFreeF next = SomeAct (() -> next)
deriving instance (Functor SomeFreeF)
makeFree ''SomeFreeF
runSomeFree :: SomeFree IO () -> IO ()
runSomeFree = inner Nothing
where
inner mval =
iterT \case
SomeAct f -> do
case mval of
Nothing -> do
a <- init
inner (Just a) (FT someAct f ??)
-- How to continue the inner loop with
-- the new state and the continuation `f`?
Just a -> do
f a
最佳答案
正如我在评论中指出的,乍一看,这似乎是 iterTM
的工作。 ,就像 iterT
除了它在您选择的 monad 转换器中运行。
iterTM :: (Functor f, Monad m, MonadTrans t, Monad (t m)) => (f (t m a) -> t m a) -> FreeT f m a -> t m a
iterTM f (FreeT m) = do -- running in the output monad `t`
val <- lift m
case fmap (iterTM f) val of -- fold the children first
Pure x -> return x
Free y -> f y
你可以选择输出 monad
t
,但是 m
和 a
由 FreeT
定义您正在折叠的数据结构。对于每一层FreeT
,从底部开始,iterTM
通过 f
充满了将图层的子元素折叠到回调中的结果。您可以决定如何处理这些 monadic 结果(在它们之间进行选择,对它们进行排序,等等)。您提到在
StateT
中进行折叠,但您给出的示例代码看起来更像是 ReaderT
对我来说。 (您不会从每次迭代中返回修改后的状态 - 只是向下传递修改后的参数。)runSomeFree :: Monad m => SomeFree m a -> ReaderT (Maybe ()) m a
runSomeFree = iterTM go
where
go (SomeAct f) = ask >>= \case
Just () -> f ()
Nothing -> local (const $ Just ()) (f ())
关于haskell - 如何使免费的 monad 解释器递归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62444355/