为多变函数键入约束,例如lift

时间:2015-09-15 09:38:03

标签: haskell typeclass monad-transformers type-constraints lifting

所以我有这个代码

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import MonadA

data A = A

newtype MonadA a => MyStateT a b { runMyStateT :: StateT A a b }
    deriving (Functor, Applicative, Monad, MonadIO, MonadState A)

instance MonadTrans MyStateT where
    lift = MyStateT . lift

我让编译器抱怨它无法证明m的签名中的lift属于MonadA类型,或者我是如何读取这些神秘的错误消息。

Could not deduce (MonadA m) arising from a use of `MyStateT'
from the context (Monad m)
  bound by the type signature for
             lift :: Monad m => m a -> MyStateT m a

有没有办法解决这个问题?我想我需要约束才能实例化如下:

instance MonadA a => MonadA (MyStateT a) where
    f = MyStateT . lift . f

f的这种实现也会起作用吗? (由于上述错误,我没有那么远)。我希望右侧的f能够通过内部monad f解析a

编辑:确实有助于删除newtype MonadA a => MyStateT ...中的类型约束,以避免我提到的确切错误。然而,我之前只有另一个错误归因于同样的事情,请考虑上面示例代码的这种延续(某些部分重复,现在没有类型约束):

class MonadB m where
    fB :: m ()

newtype MyStateT m a = MyStateT { runMyStateT :: StateT A m a}
    deriving (... MonadState A ...)

instance MonadTrans MyStateT where
    lift = MyStateT . lift

instance MonadA a => MonadA (MyStateT a) where
    f = lift . f

instance MonadA a => MonadB (MyStateT a) where
    fB = lift (modify (...))

错误是

Could not deduce (a ~ StateT A m0) from context (MonadA (MyStateT a), MonadA a)

fB的实施中。早些时候我试过class MonadA m => MonadB m无济于事。将aStateT A m匹配甚至没有意义。由于MyStateTMonadState A的一个实例,它应该有效,不是吗?

修改

好的,让它运转起来:

fB = MyStateT (modify ...)
愚蠢我。

1 个答案:

答案 0 :(得分:4)

解决方案是从MyStateT定义中删除约束:

newtype MyStateT a b { runMyStateT :: StateT A a b }
    deriving (Functor, Applicative, Monad, MonadIO, MonadState A)

数据类型约束基本上是无用的,因为您无论如何都需要将它们放入函数签名中。因此,该功能实际上是deprecated

  

我认为我需要约束才能实例化如下:

不是真的;如果没有它,instance MonadA a => MonadA (MyStateT a)会正常工作。

  

f的这种实现也会起作用吗?

会的。请注意,当您为MonadTrans提供MyStateT实例时,实际上并不需要明确地使用MyStateT包装:

instance MonadA a => MonadA (MyStateT a) where
    f = lift . f