Movatterモバイル変換
[0]ホーム
{-# LANGUAGE NoImplicitPrelude #-}{-# LANGUAGE Unsafe #-}{-# OPTIONS_HADDOCK hide #-}------------------------------------------------------------------------------- |-- Module : Control.Monad.ST.Imp-- Copyright : (c) The University of Glasgow 2001-- License : BSD-style (see the file libraries/base/LICENSE)---- Maintainer : libraries@haskell.org-- Stability : experimental-- Portability : non-portable (requires universal quantification for runST)---- This library provides support for /strict/ state threads, as-- described in the PLDI \'94 paper by John Launchbury and Simon Peyton-- Jones /Lazy Functional State Threads/.-------------------------------------------------------------------------------moduleControl.Monad.ST.Imp(-- * The 'ST' MonadST,-- abstract, instance of Functor, Monad, Typeable.runST,fixST,-- * Converting 'ST' to 'IO'RealWorld,-- abstractstToIO,-- * Unsafe operationsunsafeInterleaveST,unsafeDupableInterleaveST,unsafeIOToST,unsafeSTToIO)whereimportGHC.ST(ST,runST,unsafeInterleaveST,unsafeDupableInterleaveST)importGHC.Base(RealWorld,($),return)importGHC.IO(stToIO,unsafeIOToST,unsafeSTToIO,unsafeDupableInterleaveIO)importGHC.MVar(readMVar,putMVar,newEmptyMVar)importControl.Exception.Base(catch,throwIO,NonTermination(..),BlockedIndefinitelyOnMVar(..))-- | Allow the result of a state transformer computation to be used (lazily)-- inside the computation.---- Note that if @f@ is strict, @'fixST' f = _|_@.fixST::(a->STsa)->STsa-- See Note [fixST]fixSTk=unsafeIOToST$dom<-newEmptyMVarans<-unsafeDupableInterleaveIO(readMVarm`catch`\BlockedIndefinitelyOnMVar->throwIONonTermination)result<-unsafeSTToIO(kans)putMVarmresultreturnresult{- Note [fixST] ~~~~~~~~~~~~For many years, we implemented fixST much like a pure fixpoint,using liftST: 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 #)We knew that lazy blackholing could cause the computation to be re-run if theresult was demanded strictly, but we thought that would be okay in the case ofST. However, that is not the case (see Trac #15349). Notably, the first timethe computation is executed, it may mutate variables that cause it to behave*differently* the second time it's run. That may allow it to terminate when itshould not. More frighteningly, Arseniy Alekseyev produced a somewhat contrivedexample ( https://mail.haskell.org/pipermail/libraries/2018-July/028889.html )demonstrating that it can break reasonable assumptions in "trustworthy" code,causing a memory safety violation. So now we implement fixST much like we dofixIO. See also the implementation notes for fixIO. Simon Marlow wonderedwhether we could get away with an IORef instead of an MVar. I believe wecannot. The function passed to fixST may spark a parallel computation thatdemands the final result. Such a computation should block until the finalresult is available.-}
[8]ページ先頭