哈斯克尔。提升monad错误和本地功能

时间:2016-05-12 17:34:24

标签: haskell

    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)

如何修复它以及为什么会出错?

1 个答案:

答案 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

不确定你想在这里实现什么,但整个设计似乎......不发达。也许最好回到绘图板并弄清楚你想要什么样的架构。