Sim*_*Guy 4 monads haskell monad-transformers
我试图弄清楚如何为类型Foo 实现MonadBaseControl实例,这是一个围绕StateT实例的newtype包装器.你会认为它会像这样实现,但似乎并非如此.我假设状态片在这里引起了问题,所以有没有办法放弃它?
码:
newtype Foo a = Foo { unFoo :: StateT Int IO a }
deriving (Monad, Applicative, Functor, MonadBase IO)
instance MonadBaseControl IO Foo where
type StM Foo a = a
liftBaseWith f = Foo $ liftBaseWith $ \q -> f (q . unFoo)
restoreM = Foo . restoreM
Run Code Online (Sandbox Code Playgroud)
错误:
Couldn't match type ‘a’ with ‘(a, Int)’
‘a’ is a rigid type variable bound by
the type signature for restoreM :: StM Foo a -> Foo a
Expected type: a -> StateT Int IO a
Actual type: StM (StateT Int IO) a -> StateT Int IO a
Relevant bindings include
restoreM :: StM Foo a -> Foo a
In the second argument of ‘(.)’, namely ‘restoreM’
In the expression: Foo . restoreM
Run Code Online (Sandbox Code Playgroud)
为了避免这种情况UndecidableInstances,链接的答案扩展了一个类型系列,为了人类的可读性,它实际上不应该具有.也就是说,他写道
instance MonadBaseControl IO Foo where
type StM Foo a = a
Run Code Online (Sandbox Code Playgroud)
相反,人们可能会考虑写作
instance MonadBaseControl IO Foo where
type StM Foo a = StM (ReaderT Int IO) a
Run Code Online (Sandbox Code Playgroud)
更清楚如何为给定的新型包装选择正确的右侧.通过类似的更改(和UndecidableInstances),您的代码可以正常工作.如果你想避免UndecidableInstances,你可以在链接的答案中完成相同的扩展; 询问ghci扩展应该如下所示的示例:
> :kind! forall a. StM (StateT Int IO) a
forall a. StM (StateT Int IO) a :: *
= (a, Int)
Run Code Online (Sandbox Code Playgroud)
所以对于我们的StateT版本Foo我们也可以写:
instance MonadBaseControl IO Foo where
type StM Foo a = (a, Int)
Run Code Online (Sandbox Code Playgroud)