haskell - 如何使免费的 monad 解释器递归?
问题描述
在使用的Free monad 解释器中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
到您的回调中。您可以决定如何处理这些单子结果(在它们之间进行选择,对它们进行排序,等等)。
您提到在 a 中运行您的折叠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 ())
推荐阅读
- c# - 在面板中选择多个文本框
- php - 如何在 Laravel 中显示分组值
- javascript - 将 Html 元素转换为 JavaScript 对象
- ios - Xcode 11,使用 Main.storyboard 修复的主界面
- c# - 如何在asp.net核心中逐块从SQL Server数据库中下载文件?
- excel - 我怎样才能得到一个省略错误的平均公式
- angular - 按 ID 删除数据
- android - 为什么我不能将元素添加到地图数据类型(Dart/Flutter)
- java - 如何使用参数执行外部应用程序并接收结果
- apache-nifi - 检查 csv-header 是否正确