diff options
Diffstat (limited to 'libraries/base/GHC/ST.lhs')
-rw-r--r-- | libraries/base/GHC/ST.lhs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/libraries/base/GHC/ST.lhs b/libraries/base/GHC/ST.lhs new file mode 100644 index 0000000000..f98b33d73d --- /dev/null +++ b/libraries/base/GHC/ST.lhs @@ -0,0 +1,127 @@ +% ------------------------------------------------------------------------------ +% $Id: ST.lhs,v 1.1 2001/06/28 14:15:03 simonmar Exp $ +% +% (c) The University of Glasgow, 1992-2000 +% + +\section[GHC.ST]{The @ST@ monad} + +\begin{code} +{-# OPTIONS -fno-implicit-prelude #-} + +module GHC.ST where + +import GHC.Base +import GHC.Show +import GHC.Num + +default () +\end{code} + +%********************************************************* +%* * +\subsection{The @ST@ monad} +%* * +%********************************************************* + +The state-transformer monad proper. By default the monad is strict; +too many people got bitten by space leaks when it was lazy. + +\begin{code} +newtype ST s a = ST (STRep s a) +type STRep s a = State# s -> (# State# s, a #) + +instance Functor (ST s) where + fmap f (ST m) = ST $ \ s -> + case (m s) of { (# new_s, r #) -> + (# new_s, f r #) } + +instance Monad (ST s) where + {-# INLINE return #-} + {-# INLINE (>>) #-} + {-# INLINE (>>=) #-} + return x = ST $ \ s -> (# s, x #) + m >> k = m >>= \ _ -> k + + (ST m) >>= k + = ST $ \ s -> + case (m s) of { (# new_s, r #) -> + case (k r) of { ST k2 -> + (k2 new_s) }} + +data STret s a = STret (State# s) a + +-- liftST is useful when we want a lifted result from an ST computation. See +-- fixST below. +liftST :: ST s a -> State# s -> STret s a +liftST (ST m) = \s -> case m s of (# s', r #) -> STret s' r + +{-# NOINLINE unsafeInterleaveST #-} +unsafeInterleaveST :: ST s a -> ST s a +unsafeInterleaveST (ST m) = ST ( \ s -> + let + r = case m s of (# _, res #) -> res + in + (# s, r #) + ) + +fixST :: (a -> ST s a) -> ST s a +fixST k = ST $ \ s -> + let ans = liftST (k r) s + STret _ r = ans + in + case ans of STret s' x -> (# s', x #) + +instance Show (ST s a) where + showsPrec _ _ = showString "<<ST action>>" + showList = showList__ (showsPrec 0) +\end{code} + +Definition of runST +~~~~~~~~~~~~~~~~~~~ + +SLPJ 95/04: Why @runST@ must not have an unfolding; consider: +\begin{verbatim} +f x = + runST ( \ s -> let + (a, s') = newArray# 100 [] s + (_, s'') = fill_in_array_or_something a x s' + in + freezeArray# a s'' ) +\end{verbatim} +If we inline @runST@, we'll get: +\begin{verbatim} +f x = let + (a, s') = newArray# 100 [] realWorld#{-NB-} + (_, s'') = fill_in_array_or_something a x s' + in + freezeArray# a s'' +\end{verbatim} +And now the @newArray#@ binding can be floated to become a CAF, which +is totally and utterly wrong: +\begin{verbatim} +f = let + (a, s') = newArray# 100 [] realWorld#{-NB-} -- YIKES!!! + in + \ x -> + let (_, s'') = fill_in_array_or_something a x s' in + freezeArray# a s'' +\end{verbatim} +All calls to @f@ will share a {\em single} array! End SLPJ 95/04. + +\begin{code} +{-# INLINE runST #-} +-- The INLINE prevents runSTRep getting inlined in *this* module +-- so that it is still visible when runST is inlined in an importing +-- module. Regrettably delicate. runST is behaving like a wrapper. +runST :: (forall s. ST s a) -> a +runST st = runSTRep (case st of { ST st_rep -> st_rep }) + +-- I'm only letting runSTRep be inlined right at the end, in particular *after* full laziness +-- That's what the "INLINE 100" says. +-- SLPJ Apr 99 +{-# INLINE 100 runSTRep #-} +runSTRep :: (forall s. STRep s a) -> a +runSTRep st_rep = case st_rep realWorld# of + (# _, r #) -> r +\end{code} |