いいえ、できません。STこれらのセマンティクスはありません。モナドはST sであり、 ではありませんST s (STUArray s a)。 ST s変更可能な状態を追跡するための単なるモナドです。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 ->です。type の値Reader r aは単なる関数r -> aです。aこれは基本的に、 type の値にアクセスしながら計算する方法rです。モナド変換子はReaderT r、型の変数へのアクセスをr任意のモナド計算に提供することを可能にします。したがって、ReaderT (STUArray s Int Word32) (ST s)あるST s配列にアクセスできる計算です。から配列を返す必要がないことに注意してくださいpadFixed。モナドバインドはそのすべてを処理します。
ask配列に対して ingを保持する必要があるため、これを記述するのは少し面倒です。幸いなことに、これを処理するコンビネータをいくつか書くことができます。
{-# 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かの基本的な配列プリミティブを持ち上げて、常に利用可能なブロックで動作するようにします。必要なすべての関数を持ち上げる限り、必要がなければ型を派生させる必要さえありませMonadReaderん。Hasherしかし、一度これを行うと、ハッシュ コードは暗黙的に配列について話すことができます。