我必须做什么才能让 GHC 接受此代码:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
module STTest where
import Data.Array.ST
import Control.Monad.ST.Strict as S
import Control.Monad.ST.Lazy as L
-- ST monad arrays (unboxed in actual code)
type Arr s a = STArray s Int a
-- representing some algorithm that works on these STArrays
data ArrGen s a = ArrGen (a -> S.ST s (Arr s a)) (Arr s a -> S.ST s ())
-- class for some "generator"
class Generator g a where
gen :: g -> a -> [a]
instance Generator (ArrGen s a) a where
gen (ArrGen create apply) s = L.runST $ do
a <- strictToLazyST $ create s -- DOES NOT WORK
strictToLazyST $ apply a >> getElems a
我得到的错误如下:
Couldn't match type `s' with `s1'
`s' is a rigid type variable bound by
the instance declaration at STTest.hs:20:28
`s1' is a rigid type variable bound by
a type expected by the context: L.ST s1 [a] at STTest.hs:21:33
但是,这很好用:
data Dummy
create' :: a -> S.ST s (Arr s a)
create' = undefined
apply' :: Arr s a -> S.ST s [a]
apply' = undefined
instance Generator Dummy a where
gen _ s = L.runST $ do
a <- strictToLazyST $ create' s
strictToLazyST $ apply' a >> getElems a
为什么它适用于第二个而不是第一个?我可以如何处理数据声明以使其工作?或者我可以在实例声明中添加某种“forall”吗?
以上只是一个最小的测试程序。实际上,我永远循环应用以创建输出值的无限流。(所以我不能只是将这两个步骤合并在一起。)而且我真的希望能够为 ArrGen 数据类型实例化一次,然后使用这些 STArray 算法为其生成各种值。
编辑:
没想到将 forall 放在 ArrGen 的函数中(我把它放在整体类型上)。虽然现在我遇到了让它在 STUArray 上工作的问题。就像我使用以下内容一样:
class (Integral a, Bits a, forall s. MArray (STUArray s) a (S.ST s)) => HasSTU a
type AC a = (HasSTU a) => forall s. a -> S.ST s (STUArray s Int a)
type AU a = (HasSTU a) => forall s. STUArray s Int a -> S.ST s ()
type TX a = (HasSTU a) => a -> a -- or without the context
data ArrayGen a = AG (AC a) (AU a) (TX a)
然后这失败了:
instance (HasSTU a) => Generator (ArrayGen a) a [a] where
gens (AG c u p) s = fmap (fmap p) $ L.runST $ do
ar <- strictToLazyST $ (c s)
streamM $ strictToLazyST $ u ar >> getElems ar -- can't use getElems here!
streamM :: (Applicative f) => f a -> f (Stream a))
streamM = Cons <$> a <*> streamM a
它抱怨:
Could not deduce (MArray (STUArray s) a (S.ST s))
arising from a use of `getElems'
from the context (HasSTU a)
尽管上下文 (HasSTU a) 说(在我看来)所有 s 都有一个 (MArray (STUArray s) a (S.ST s)) 上下文,但它似乎并不这么认为。我试图通过更改(AU a)类型来修复它:
type AU a = (HasSTU a) => forall s. STUArray s Int a -> S.ST s [a]
它似乎输入检查,但我无法实际使用它。同样,如果我更改为:
class (Integral a, Bits a, forall s. MArray (STUArray s) a (S.ST s)) => HasSTU s a
type AC a = (forall s. HasSTU s a) => a -> S.ST s (STUArray s Int a)
...
instance (forall s. HasSTU s a) => Generator (ArrayGen a) a [a] where
...
instance forall s. HasSTU s Word32 -- !!!
但是当我尝试运行某些东西时:
Could not deduce (forall s. HasSTU s Word32)
我讨厌这个!为什么?我有所有s 的实例!而且我真的很迷茫,不知道我应该把我的foralls放在哪里以及到底发生了什么。