是否存在类似于可变数组的MArray类的引用的类型类?

时间:2014-01-18 20:15:37

标签: haskell typeclass mutable

MArray类提供了通用函数,用于在ST和IO上下文中处理各种类型的可变数组。我无法找到一个类似的类来处理STRefs和IORefs。这样的事情存在吗?

2 个答案:

答案 0 :(得分:6)

ref-fd包提供了它:

class Monad m => MonadRef r m | m -> r where
    [...]

或类型系列ref-tf

class Monad m => MonadRef m where
    type Ref m :: * -> *
    [...]

另一个答案表明monad-statevar包没有功能依赖。它还具有单独的HasGetHasPut成员,并且没有newRef功能的抽象。

除了每种方法中的不同方法外,功能依赖性是一种设计权衡。考虑以下两个简化类:

class MRef1 r m where
   newRef1 :: a -> m (r a)
   readRef1 :: r a -> m a

class MRef2 r m | m -> r where
   newRef2 :: a -> m (r a)
   readRef2 :: r a -> m a

使用MRef1时,monad类型和引用类型都可以自由变化,因此以下代码具有类型错误:

useMRef1 :: ST s Int
useMRef1 = do
   r <- newRef1 5
   readRef1 r

No instance for (MRef1 r0 (ST s)) arising from a use of `newRef1'
The type variable `r0' is ambiguous

我们必须在某处添加额外的类型签名,以表示我们要使用STRef

相比之下,相同的代码适用于MRef2而没有任何额外的签名。定义上的签名表示整个代码具有类型ST s Int,并结合功能依赖m -> r意味着给定r类型只有一个m类型,所以编译器知道我们现有的实例是唯一可能的实例,我们必须要使用STRef

另一方面,假设我们想要一种新的参考,例如STRefHistory跟踪所有已存储在其中的值:

newtype STRefHistory s a = STRefHistory (STRef s [a])

MRef1实例很好,因为我们允许多个引用类型用于相同的monad类型:

instance MRef1 (STRefHistory s) (ST s) where
   newRef1 a = STRefHistory <$> newSTRef [a]
   readRef1 (STRefHistory r) = head <$> readSTRef r

但是等效的MRef2实例失败了:

Functional dependencies conflict between instance declarations:
  instance MRef2 (STRef s) (ST s) -- Defined at mref.hs:28:10
  instance MRef2 (STRefHistory s) (ST s) -- Defined at mref.hs:43:10

我还提到了类型系列版本,它在功能依赖性方面表现力非常相似;引用类型是monad类型的“类型函数”,因此每个monad只能有一个。语法最终有点不同,特别是你可以在约束中说MonadRef m,而不说明约束中的引用类型。

具有相反的功能依赖性也是合理的:

class MRef2 r m | r -> m where

这样每个引用类型只能存在一个monad中,但是你仍然可以为monad提供多种引用类型。那么你需要在引用上输入类型签名,而不是整体上的monadic计算。

答案 1 :(得分:5)

Control.Monad.StateVar有一个类型类,可以让getput IORef和STRef完全相同。