Haskell 组合状态和状态转换器动作
我有几个Haskell 组合状态和状态转换器动作,haskell,monad-transformers,Haskell,Monad Transformers,我有几个Statemonad操作。一些操作根据当前状态和其他可选的生成结果的输入做出决策。这两种类型的操作相互调用 我用State和StateT-Maybe对这两种动作类型进行了建模。以下(人为的)示例显示了我当前的方法 {-# LANGUAGE MultiWayIf #-} import Control.Monad (guard) import Control.Monad.Identity (runIdentity) import Control.Monad.Trans.State typ
State
monad操作。一些操作根据当前状态和其他可选的生成结果的输入做出决策。这两种类型的操作相互调用
我用State
和StateT-Maybe
对这两种动作类型进行了建模。以下(人为的)示例显示了我当前的方法
{-# LANGUAGE MultiWayIf #-}
import Control.Monad (guard)
import Control.Monad.Identity (runIdentity)
import Control.Monad.Trans.State
type Producer = Int -> State [Int] Int
type MaybeProducer = Int -> StateT [Int] Maybe Int
produce :: Producer
produce n
| n <= 0 = return 0
| otherwise = do accum <- get
let mRes = runStateT (maybeProduce n) accum
if | Just res <- mRes -> StateT $ const (return res)
| otherwise -> do res <- produce (n - 1)
return $ res + n
maybeProduce :: MaybeProducer
maybeProduce n = do guard $ odd n
modify (n:)
mapStateT (return . runIdentity) $
do res <- produce (n - 1)
return $ res + n
{-#语言多路If}
进口管制.单子(警卫)
导入控制.Monad.Identity(runIdentity)
进口管制.单子.跨州
类型Producer=Int->State[Int]Int
键入MaybeProducer=Int->StateT[Int]Maybe Int
生产者
产生
|n
我也不想将状态
操作提升到状态,因为它可能会造成不准确的模型
你说的“推广”是什么意思?我不知道你指的是哪一个:
重写状态
操作的定义,使其类型现在为StateT Maybe
,即使它们根本不依赖Maybe
李>
使用适配器函数将状态s a
转换为状态s可能是a
我同意拒绝(1),但对我而言,这意味着:
- 选择(2)。一个有用的工具是使用()李>
- 重写来自
状态sa
的操作,以使用单子m=>StateT s m a
在第二种情况下,类型与任何Monadm
兼容,但不允许代码采用任何特定的基Monad,因此可以获得与状态sa
相同的纯度
我想试一试。请注意:
State s a
=StateT s Identity a
李>
提升机概括::(MFunctor t,Monad m)=>t标识a->t m a
李>
- 它专门用于提升泛化::State sa->StateT s可能是一个
李>
编辑:毫无意义的是,所有m的状态sa
和之间存在同构。StateT s m a
类型,由以下反函数给出:
{-# LANGUAGE RankNTypes #-}
import Control.Monad.Morph
import Control.Monad.Trans
import Control.Monad.Trans.State
import Control.Monad.Identity
fwd :: (MFunctor t, Monad m) => t Identity a -> t m a
fwd = hoist generalize
-- The `forall` in the signature forbids callers from demanding any
-- specific choice of type for `m`, which allows *us* to choose
-- `Identity` for `m` here.
bck :: MFunctor t => (forall m. t m a) -> t Identity a
bck = hoist generalize
因此,Monad m=>StateT s m a
和mmorph
解决方案实际上是相同的。不过,我更喜欢在这里使用mmorph
。mapStateT
很好,我只想使用而已。runIdentity
作为它的论据。大致相同的问题(虽然理论性更强):是的,我指的是(1)。Monad m=>StateT s m a
是一个巧妙的技巧,尽管不是很明显,从API的角度来看,我觉得有点误导。当然,这完全有道理——“我不依赖于内在单子的类型”mmorph
看起来是这项工作的合适工具,谢谢。“Monad m=>StateT s m a是一个巧妙的技巧,虽然不是很明显,但从API的角度来看,我觉得有点误导。”我同意它不太清楚,但严格来说,它不会误导人,因为类型将同构于State s a
。请参阅我对答案的编辑。