モナド内のsオブジェクトがSTモナドの外側に漏れないようにしSTます。
-- This is an error... but let's pretend for a moment...
let a = runST $ newSTRef (15 :: Int)
b = runST $ writeSTRef a 20
c = runST $ readSTRef a
in b `seq` c
STRefさて、これは型エラーです(これは良いことです!元の計算の外に漏れたくないです!)。余分なため、タイプエラーですs。runST署名があることを忘れないでください:
runST :: (forall s . ST s a) -> a
これは、s実行している計算に制約がないことを意味します。したがって、評価しようとするとa:
a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))
結果はタイプがなりますが、はinの外側に「エスケープ」されてSTRef s Intいるため、これは誤りです。型変数は常にの内側に現れる必要があり、Haskellはどこでも暗黙の数量詞を許可します。のリターンタイプを意味のある形で把握できるルールはありません。sforallrunSTforallforalla
別の例forall:物事をエスケープできない理由を明確に示すために、次forallの簡単な例を示します。
f :: (forall a. [a] -> b) -> Bool -> b
f g flag =
if flag
then g "abcd"
else g [1,2]
> :t f length
f length :: Bool -> Int
> :t f id
-- error --
もちろんf id、エラーです。ブール値がtrueかfalseかCharに応じて、のリストまたはリストが返されるためです。Intの例のように、それは単に間違っていSTます。
一方、 typeパラメーターがない場合はs、コードが明らかにかなり偽物であっても、すべてが正常に型チェックされます。
STの実際の動作:実装に関しては、STモナドは実際にはモナドと同じですが、IOインターフェイスが少し異なります。STあなたが実際に得るモナドunsafePerformIOまたは同等のものを舞台裏で使用するとき。これを安全に実行できる理由は、ST関連するすべての関数、特に。を含む部分の型アノテーションのためforallです。