Haskell:将类型别名更改为newtype会产生错误

时间:2014-08-16 06:50:51

标签: haskell newtype

在我的库中,我想在文档中向用户公开底层monadic状态的名称,但我不希望它们能够拆开它 - 我想制作一个黑盒子。

因此,我开始使用以下类型别名完全使用代码:

type Surge e c z m = ErrorT (Failure z) (ReaderT (SurgeChan e c) (Parser' ByteString m))

然后,为了使其更加健壮,我将其更改为newtype并启用了GeneralizedNewtypeDeriving

newtype Surge e c z m a = Surge
    { runSurge' :: ErrorT (Failure z) (ReaderT (SurgeChan e c) (Parser' ByteString m)) a }
    deriving (Monad, Applicative, Functor)

我有一些其他代码需要像这样调整:

res <- flip St.evalStateT prod . flip runReaderT sc . runErrorT $ pipeline

==&GT;

res <- flip St.evalStateT prod . flip runReaderT sc . runErrorT . runSurge' $ pipeline

不幸的是,由于某种原因,在我进行type - &gt; newtype更改后,并非所有代码都会进行类型检查。这部分代码特别是:

{-# INLINE decodeAndHandlePacket #-}
decodeAndHandlePacket
    = handlePacket ~< errorP (lift.lift.liftM (first DecodeFailure) . decodeGet $ decodePacket)

...现在没有出现相当长的错误,但之前没有:

src/Surge/Internal.hs:101:27:
    Couldn't match type ‘ErrorT
                           (Failure z0) (t0 (St.StateT (Producer ByteString m0 x0) m0))’
                  with ‘Surge e c z m’
    Expected type: Proxy a' a () p' (Surge e c z m) ByteString
      Actual type: Proxy
                     a'
                     a
                     ()
                     p'
                     (ErrorT
                        (Failure z0) (t0 (St.StateT (Producer ByteString m0 x0) m0)))
                     ByteString
    Relevant bindings include
      decodeAndHandlePacket :: Proxy a' a () p' (Surge e c z m) ()
        (bound at src/Surge/Internal.hs:100:5)
      handleCommand :: Handler c p' (Surge e c z m)
        (bound at src/Surge/Internal.hs:84:7)
      handleEvent :: Handler e p' (Surge e c z m)
        (bound at src/Surge/Internal.hs:84:7)
      handlePacket :: Handler ByteString p' (Surge e c z m)
        (bound at src/Surge/Internal.hs:84:7)
      stage :: Stage ByteString p' e c (Surge e c z m)
               -> Producer ByteString (Surge e c z m) ()
        (bound at src/Surge/Internal.hs:84:1)
    In the second argument of ‘(~<)’, namely
      ‘errorP
         (lift . lift . liftM (first DecodeFailure) . decodeGet
          $ decodePacket)’
    In the expression:
      handlePacket
      ~<
        errorP
          (lift . lift . liftM (first DecodeFailure) . decodeGet
           $ decodePacket)

我不知道该怎么做。双方看起来和我一模一样。

http://lpaste.net/109472提供完整代码。感谢。

2 个答案:

答案 0 :(得分:3)

decodeAndHandlePacket期望处理Surge e c z m,但是你给它一个(ErrorT (Failure z0) (t0 (St.StateT (Producer ByteString m0 x0) m0))),即你没有用Surge构造函数包装它。当您使用newtype包装器包装类型时,您必须确保在任何地方执行包装和解包。

答案 1 :(得分:1)

你想要

decodeAndHandlePacket
        = handlePacket ~< hoist Surge (errorP (lift.lift.liftM (first DecodeFailure) . decodeGet $ decodePacket))

请注意,errorP调用的返回类型为

Proxy a'0 a0 () p' (ErrorT (Failure ...)) ByteString

并且您想要用newtype替换第五个参数,即

Proxy a'0 a0 () p' (Surge e c z m) ByteString

此newtype是monad(类型构造函数),您需要将hoist中的(ErrorT (Failure ...))中的操作导入(Surge ...) monad。