モナド内の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はどこでも暗黙の数量詞を許可します。のリターンタイプを意味のある形で把握できるルールはありません。s
forall
runST
forall
forall
a
別の例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
です。