我正在使用免费库中的FreeT类型来编写这个“运行”底层的函数:StateT
runStateFree
:: (Functor f, Monad m)
=> s
-> FreeT f (StateT s m) a
-> FreeT f m (a, s)
runStateFree s0 (FreeT x) = FreeT $ do
flip fmap (runStateT x s0) $ \(r, s1) -> case r of
Pure y -> Pure (y, s1)
Free z -> Free (runStateFree s1 <$> z)
但是,我正在尝试将其转换为FT,教堂编码版本,而不是:
runStateF
:: (Functor f, Monad m)
=> s
-> FT f (StateT s m) a
-> FT f m (a, s)
runStateF s0 (FT x) = FT $ \ka kf -> ...
但我的运气不太一样。我得到的每一种组合似乎都不太奏效。我得到的最接近的是
runStateF s0 (FT x) = FT $ \ka kf ->
ka =<< runStateT (x pure (\n -> _ . kf (_ . n)) s0
但是第一个洞m r -> StateT s m r
的类型是,第二个洞的类型是StateT s m r -> m r
......这意味着我们必然会在这个过程中失去状态。
我知道所有FreeT
功能都可以用FT
. 有没有一种不涉及往返的好方法来编写这个FreeT
(也就是说,以一种需要明确匹配Pure
and的方式Free
)?(我尝试过手动内联事物,但我不知道如何使用s
定义中的不同 s来处理递归runStateFree
)。或者这可能是显式递归数据类型必然比教堂(mu)编码更高效的情况之一?