代码之家  ›  专栏  ›  技术社区  ›  jakubdaniel

多态函数(如lift)的类型约束

  •  0
  • jakubdaniel  · 技术社区  · 9 年前

    所以我有这个代码

    {-# 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 在右侧解决 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 但没有用。匹配甚至没有意义 具有 StateT A m 自从 MyStateT 是的实例 MonadState A 它应该有用,不是吗?

    编辑 :

    好了,开始工作了:

    fB = MyStateT (modify ...)
    

    愚蠢的我。

    1 回复  |  直到 9 年前
        1
  •  4
  •   duplode    9 年前

    解决方案是从 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 的实例 我的状态T ,你实际上不需要用 我的状态T 明确地:

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