2013-07-19 51 views
3

我有什麼做的,使GHC接受這個代碼:ST(U)數組在數據結構中?

{-# 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 

爲什麼它與第二個而不是第一個一起工作?我可以通過數據聲明來做些什麼?或者我可以在實例聲明中添加某種「全部」?

以上只是一個簡單的測試程序。我實際上循環應用永遠創建一個無限的輸出值流。 (所以我不能將這兩個步驟合併在一起。)我真的希望能夠爲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一)說,(在我的腦海)那對於所有的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!爲什麼?我有一個所有 s!我真的失去了應該在哪裏放置我的論文以及發生了什麼。

回答

2

的問題是,runST需要一個forall s. ST s t的說法,但你的類型修復s,所以在單子行動使用createapply使得它不適合runST

這並不在我看來,您的使用情況下,禁止給ArrGen多態性(在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

+1

謝謝你的回答!它讓我更靠近了一步......但我仍然無法使用STUArray。這非常令人沮喪!而且我已經接近放棄,並且始終只使用IArray,因爲ST monad讓我感覺完全失去了。我更新了我的問題,那裏有任何想法? – integer

+0

編譯器是不是已經在class上完全禁用了(整數a,位a,全部s。MArray(STUArray s)a(S.ST s))=> HasSTU a'?如果不是,那麼什麼時候允許'forall'ed上下文呢?無論如何,沒有直接的想法如何做到這一點。如何使它成爲非ST的東西,並在每一步中使用'runST','unsafeThaw','unsafeFreeze'? –