3

我必须做什么才能让 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放在哪里以及到底发生了什么。

4

1 回答 1

2

问题是这runST需要一个forall s. ST s t参数,但是您的类型修复s了 ,因此在单子动作中使用createandapply使其不适合runST.

在我看来,您的用例并不禁止提供ArrGen多态(in s)参数,所以

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, RankNTypes #-}

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 a = ArrGen (forall s. a -> S.ST s (Arr s a)) (forall s. Arr s a -> S.ST s ())

-- class for some "generator"
class Generator g a where
  gen :: g -> a -> [a]

instance Generator (ArrGen a) a where
  gen (ArrGen create apply) s = L.runST $ do
    a <- strictToLazyST $ create s -- DOES NOT WORK
    strictToLazyST $ apply a >> getElems a

使组件多态工作(至少在它编译的意义上,您的用例可能会禁止这种方法)。

为什么它适用于第二个而不是第一个?

因为在那里,s没有固定,计算在 中是完全多态的s,正如 所要求的那样runST

于 2013-07-19T09:14:17.017 回答