0

我想将状态单子转换器的状态参数的类型设置为该单子转换器的关联类型。但是,这会导致构造一个无限类型,

s = AssocTyp (StateT s m) a

关于为什么这不是一个真正的问题的直觉是,

AssocTyp (StateT s m) a = AssocTyp (StateT s' m) a

对于所有ss'。但是,编译器不够聪明,无法解决这个问题。我读过,在某些情况下,可以使用 newtype 来避免无限类型;我该怎么做?

这是重现问题的最小化代码,

{-# LANGUAGE KindSignatures, TypeFamilies #-}

import Control.Monad.Trans.State

class MyMonad (m :: * -> *) where
    data AssocTyp m :: * -> *

instance MyMonad m => MyMonad (StateT s m) where
    data AssocTyp (StateT s m) a = StateTA (AssocTyp m a)

isAssocTyp :: Monad m => (AssocTyp m a) -> m ()
isAssocTyp x = return ()

x = do
    v <- get
    isAssocTyp (v)
4

2 回答 2

3

我不确定你想要达到什么目的。然而,你所说的平等,

AssocTyp (StateT s m) a = AssocTyp (StateT s' m) a

不正确,因为您使用的是数据系列而不是类型系列。以下代码编译:

{-# LANGUAGE KindSignatures, TypeFamilies #-}

import Control.Monad.Trans.State

class MyMonad (m :: * -> *) where
    type AssocTyp m :: * -> *

instance MyMonad m => MyMonad (StateT s m) where
    type AssocTyp (StateT s m) = AssocTyp m

isAssocTyp :: Monad m => (AssocTyp m a) -> m ()
isAssocTyp x = return ()

x :: Monad m => StateT (AssocTyp m a) m ()
x = do
    v <- get
    isAssocTyp v

类型族和数据族之间的区别在于数据族是单射的,这意味着如果是数据族,则以下含义成立DF

DF a b c = DF a' b' c'   =====>     a = a',   b = b',   c = c'

这不是你想要的。

于 2012-03-26T23:53:22.670 回答
0

以防万一数据系列是您想要的,我有一个可以进行类型检查的变体:

isAssocType' :: (Monad m1, Monad m0) => (AssocTyp m1 a) -> m0 ()
isAssocType' _ = return ()
于 2012-03-26T23:58:26.367 回答