いいえ、できません。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
しかし、一度これを行うと、ハッシュ コードは暗黙的に配列について話すことができます。