【发布时间】:2015-03-29 19:31:07
【问题描述】:
-- InternalComponent.hs
data ComponentState = ComponentState ...
instance Default ComponentState where ...
componentFunction :: (MonadState InternalComponentState m) => a -> m a
-- Program.hs
data ProgramState = forall cs. ProgramState {
componentState :: cs,
...
}
newtype MyMonad a = MyMonad { runMyMonad :: StateT ProgramState IO a }
myFunction a = do
s <- get
let cs = componentState s
let (r, cs') = runState (componentFunction a) cs
put $ s { componentState = cs' }
return r
我想要的是能够使用MyMonad 内部的componentFunction(在myFunction 中,如示例中所示),而不对组件所需状态的实际类型特别感兴趣。将组件状态保持在我自己的状态中不是必需的,但就我在 Haskell 中使用状态的能力而言。
这实际上可以看作是在另一种编程语言中实现的有状态接口的等价物:具有某些实现的接口的实例化提供默认状态值,并且通过该接口调用的每个函数都可以修改该状态。在任何时候都不会向用户展示实现细节。
如果不清楚,上面的例子失败了,因为myFunction的实现不能证明记录选择器提供了一个合适的类型(因为它是一个存在的);至少我是这么理解的。
【问题讨论】:
-
你的
ProgramState真的没有意义。您是说有一个名为componentState的字段,其类型完全未知。您不能从componentState字段神奇地“生成”ComponentState类型的值,因为您已经对类型变量cs进行了存在量化——cs的类型不再对外界可见。您是正确的,“myFunction 无法证明记录选择器提供了适当的类型”。显而易见的解决方案是不量化cs- 在这种情况下,您完全不清楚为什么要这样做。 -
这可能是相关的:Combining multiple states in StateT。