data InterpreterM a = ExeInterpreter a | PropInterpreter a
newtype InterpreterMT m a = InterpreterMT { runInterpreterMT :: m (InterpreterM a) }
type Interpreter = InterpreterMT (StateT Int (ReaderT Int (ErrorT String IO)))
data Stmts = Statements Stmt Stmts | EmptyStmts
instance (Monad m) => Monad (InterpreterMT m) where
return x = InterpreterMT $ return (ExeInterpreter x)
x >>= f = InterpreterMT $ do
m <- runInterpreterMT x
case m of
(ExeInterpreter a) -> runInterpreterMT (f a)
interpreter :: Stmts -> Interpreter ()
interpreter EmptyStmts = return ()
interpreter (Statements s stmts) = lift $ local (\x -> x) (interpreter stmts)
instance MonadTrans InterpreterMT where
lift m = InterpreterMT $ do
x <- m
return $ ExeInterpreter x
编译器在最后一行给了我更多的信息:
Couldn't match type `InterpreterMT
(StateT Int (ReaderT Int (ErrorT String IO)))'
with `StateT Int (ReaderT Int (ErrorT String IO))'
Expected type: Interpreter ()
Actual type: InterpreterMT
(InterpreterMT (StateT Int (ReaderT Int (ErrorT String IO)))) ()
In the expression: lift $ local (\ x -> x) (interpreter stmts)
In an equation for `interpreter':
interpreter (Statements s stmts)
= lift $ local (\ x -> x) (interpreter stmts)
如何修复它以及为什么会出错?
答案 0 :(得分:1)
好的,有两个问题。
首先,lift
具有以下签名:
lift :: (MonadTrans t, Monad m) => m a -> t m a
所以你必须提供未经改造的monadic动作才能解除。换句话说,您不能在InterpreterMT
的参数中使用lift
。
所以你需要打开它:
lift $ local id $ runInterpreterMT $ interpreter stmts
但是现在你的返回类型没有意义:runInterpreterMT $ ...
有类型
StateT Int (ReaderT Int (ErrorT String IO)) (InterpreterM ())
或者,将变压器堆栈缩短为M
,
M (InterpreterM ())
而interpreter
返回Interpreter ()
,即
InterpreterMT (StateT Int (ReaderT Int (ErrorT String IO))) ()
或缩短变压器堆栈,
InterpreterMT M ()
返回lift
类型,m a -> t m a
变为M (InterpreterM ()) -> InterpreterMT M (InterpreterM ())
。 (InterpreterM ())
不 ()
。
问题的根源?你的InterpreterMT
实际上不是monad变换器,因为它并没有真正改变monad。它改变了价值。
轻松修复?如果您可以为Monad
找出合理的InterpreterMT
实例(您提供的实例值得怀疑),则可以为MonadReader
定义InterpreterMT
实例:
instance MonadReader r m => MonadReader r (InterpreterMT m) where
local f = InterpreterMT . local f . runInterpreterMT
...
(此特定定义需要UndecideableInstances
)
一般模式似乎是
inInterpreter f = InterpreterMT . f . runInterpreterMT
请注意,这是不 a Functor
。
不确定你想在这里实现什么,但整个设计似乎......不发达。也许最好回到绘图板并弄清楚你想要什么样的架构。