不,這是不可能的; ST
沒有這些語義。單子是ST s
,而不是ST s (STUArray s a)
。 ST s
只是一個用於跟蹤可變狀態的monad;您選擇在單個ST
區域內分配和使用的結構由您決定。如果你有一大堆的計算,所有在同一STUArray
操作,您可以使用ReaderT
:
type Hasher s = ReaderT (STUArray s Int Word32) (ST s)
padFixed :: Hasher()
padFixed = do
block <- ask
unsafeWrite block 5 0x80000000
unsafeWrite block 15 160
的Reader r
單子只是一個圍繞r ->
包裝;類型Reader r a
的值只是一個函數r -> a
。這實際上是一種計算a
,同時可以訪問類型r
的值的方法。 ReaderT r
monad變換器只允許您提供對r
類型的變量的訪問以進行任意一次性計算;因此,ReaderT (STUArray s Int Word32) (ST s)
是一個ST s
計算,它可以訪問某個數組。請注意,您不需要從padFixed
返回數組; monad綁定將處理所有這些。
這將是一個痛苦的一點點寫的,因爲我們必須要保持ask
荷蘭國際集團的陣列。幸運的是,我們可以寫一些組合子來處理這個我們:
{-# LANGUAGE RankNTypes, GeneralizedNewtypeDeriving #-}
import Data.Word
import Control.Applicative
import Control.Monad.Reader
import Control.Monad.ST
import Data.Array.ST (STUArray, runSTUArray)
import qualified Data.Array.Base as A
import Data.Array.Unboxed (UArray)
newtype Hasher s a =
Hasher { getHasher :: ReaderT (STUArray s Int Word32) (ST s) a }
deriving (Functor, Applicative, Monad, MonadReader (A.STUArray s Int Word32))
hasherToST :: Hasher s() -> (Int,Int) -> ST s (STUArray s Int Word32)
hasherToST (Hasher r) bounds = do
block <- A.newArray bounds 0
runReaderT r block
return block
runHasher :: (forall s. Hasher s()) -> (Int,Int) -> UArray Int Word32
runHasher h bounds = runSTUArray $ hasherToST h bounds
-- Perhaps private to this module, perhaps not
liftST :: ST s a -> Hasher s a
liftST = Hasher . lift
----- We can lift the functions which act on an STUArray -----
getBounds :: Hasher s (Int,Int)
getBounds = liftST . A.getBounds =<< ask
-- I'd recommend against removing the `unsafe` from the name; this function
-- could segfault, after all.
unsafeReadBlock :: Int -> Hasher s Word32
unsafeReadBlock i = do
block <- ask
liftST $ A.unsafeRead block i
unsafeWriteBlock :: Int -> Word32 -> Hasher s()
unsafeWriteBlock i x = do
block <- ask
liftST $ A.unsafeWrite block i x
----- And then, perhaps in a separate module: -----
padFixed :: Hasher s()
padFixed = do
unsafeWriteBlock 5 0x80000000
unsafeWriteBlock 15 160
(請注意,我不能內嵌hasherToST
的runHasher
內,可能是因爲較高等級類型的封鎖推斷。)
基本上,我們將ReaderT (STUArray s Int Word32) (ST s)
換成newtype
而不是類型同義詞,並將一些基本數組原語提起來,以便在始終可用的塊上工作。如果您不需要,您甚至不需要爲Hasher
類型派生MonadReader
,只要您解除所有必要的功能即可。但是一旦你完成了這些,你的哈希代碼可以隱式地討論這個數組。
感謝您的徹底解答。我不確定使用'ReaderT' monad是否僅僅使用我當前擁有的簽名(可能會使用'type'替代別名)來購買我,但我需要反思一下你的答案。 – Ralph