diff options
Diffstat (limited to 'libraries/base/Control/Monad')
-rw-r--r-- | libraries/base/Control/Monad/Fail.hs | 4 | ||||
-rw-r--r-- | libraries/base/Control/Monad/Fix.hs | 28 | ||||
-rw-r--r-- | libraries/base/Control/Monad/ST.hs | 2 | ||||
-rw-r--r-- | libraries/base/Control/Monad/ST/Imp.hs | 58 | ||||
-rw-r--r-- | libraries/base/Control/Monad/ST/Lazy/Imp.hs | 16 | ||||
-rw-r--r-- | libraries/base/Control/Monad/ST/Lazy/Safe.hs | 2 | ||||
-rw-r--r-- | libraries/base/Control/Monad/ST/Lazy/Unsafe.hs | 2 | ||||
-rw-r--r-- | libraries/base/Control/Monad/Zip.hs | 14 |
8 files changed, 105 insertions, 21 deletions
diff --git a/libraries/base/Control/Monad/Fail.hs b/libraries/base/Control/Monad/Fail.hs index 91ef3ed349..ecf974bc79 100644 --- a/libraries/base/Control/Monad/Fail.hs +++ b/libraries/base/Control/Monad/Fail.hs @@ -50,13 +50,13 @@ import {-# SOURCE #-} GHC.IO (failIO) -- only a single data constructor, and irrefutable patterns (@~pat@). -- -- Instances of 'MonadFail' should satisfy the following law: @fail s@ should --- be a left zero for '>>=', +-- be a left zero for 'Control.Monad.>>=', -- -- @ -- fail s >>= f = fail s -- @ -- --- If your 'Monad' is also 'MonadPlus', a popular definition is +-- If your 'Monad' is also 'Control.Monad.MonadPlus', a popular definition is -- -- @ -- fail _ = mzero diff --git a/libraries/base/Control/Monad/Fix.hs b/libraries/base/Control/Monad/Fix.hs index c8a9ddab58..f287b06541 100644 --- a/libraries/base/Control/Monad/Fix.hs +++ b/libraries/base/Control/Monad/Fix.hs @@ -28,18 +28,19 @@ import Data.Either import Data.Function ( fix ) import Data.Maybe import Data.Monoid ( Dual(..), Sum(..), Product(..) - , First(..), Last(..), Alt(..) ) -import GHC.Base ( Monad, errorWithoutStackTrace, (.) ) + , First(..), Last(..), Alt(..), Ap(..) ) +import Data.Ord ( Down(..) ) +import GHC.Base ( Monad, NonEmpty(..), errorWithoutStackTrace, (.) ) import GHC.Generics import GHC.List ( head, tail ) -import GHC.ST +import Control.Monad.ST.Imp import System.IO -- | Monads having fixed points with a \'knot-tying\' semantics. -- Instances of 'MonadFix' should satisfy the following laws: -- -- [/purity/] --- @'mfix' ('return' . h) = 'return' ('fix' h)@ +-- @'mfix' ('Control.Monad.return' . h) = 'Control.Monad.return' ('fix' h)@ -- -- [/left shrinking/ (or /tightening/)] -- @'mfix' (\\x -> a >>= \\y -> f x y) = a >>= \\y -> 'mfix' (\\x -> f x y)@ @@ -74,6 +75,14 @@ instance MonadFix [] where [] -> [] (x:_) -> x : mfix (tail . f) +-- | @since 4.9.0.0 +instance MonadFix NonEmpty where + mfix f = case fix (f . neHead) of + ~(x :| _) -> x :| mfix (neTail . f) + where + neHead ~(a :| _) = a + neTail ~(_ :| as) = as + -- | @since 2.01 instance MonadFix IO where mfix = fixIO @@ -118,6 +127,10 @@ instance MonadFix Last where instance MonadFix f => MonadFix (Alt f) where mfix f = Alt (mfix (getAlt . f)) +-- | @since 4.12.0.0 +instance MonadFix f => MonadFix (Ap f) where + mfix f = Ap (mfix (getAp . f)) + -- Instances for GHC.Generics -- | @since 4.9.0.0 instance MonadFix Par1 where @@ -137,3 +150,10 @@ instance (MonadFix f, MonadFix g) => MonadFix (f :*: g) where where fstP (a :*: _) = a sndP (_ :*: b) = b + +-- Instances for Data.Ord + +-- | @since 4.12.0.0 +instance MonadFix Down where + mfix f = Down (fix (getDown . f)) + where getDown (Down x) = x diff --git a/libraries/base/Control/Monad/ST.hs b/libraries/base/Control/Monad/ST.hs index 8313c2d3eb..6f1dc31e38 100644 --- a/libraries/base/Control/Monad/ST.hs +++ b/libraries/base/Control/Monad/ST.hs @@ -16,7 +16,7 @@ -- -- References (variables) that can be used within the @ST@ monad are -- provided by "Data.STRef", and arrays are provided by --- "Data.Array.ST". +-- [Data.Array.ST](https://hackage.haskell.org/package/array/docs/Data-Array-ST.html). ----------------------------------------------------------------------------- diff --git a/libraries/base/Control/Monad/ST/Imp.hs b/libraries/base/Control/Monad/ST/Imp.hs index c053dcc64d..55bd780f2c 100644 --- a/libraries/base/Control/Monad/ST/Imp.hs +++ b/libraries/base/Control/Monad/ST/Imp.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE Unsafe #-} {-# OPTIONS_HADDOCK hide #-} @@ -23,7 +24,7 @@ module Control.Monad.ST.Imp ( runST, fixST, - -- * Converting 'ST' to 'IO' + -- * Converting 'ST' to 'Prelude.IO' RealWorld, -- abstract stToIO, @@ -34,7 +35,56 @@ module Control.Monad.ST.Imp ( unsafeSTToIO ) where -import GHC.ST ( ST, runST, fixST, unsafeInterleaveST +import GHC.ST ( ST, runST, unsafeInterleaveST , unsafeDupableInterleaveST ) -import GHC.Base ( RealWorld ) -import GHC.IO ( stToIO, unsafeIOToST, unsafeSTToIO ) +import GHC.Base ( RealWorld, ($), return ) +import GHC.IO ( stToIO, unsafeIOToST, unsafeSTToIO + , unsafeDupableInterleaveIO ) +import GHC.MVar ( readMVar, putMVar, newEmptyMVar ) +import Control.Exception.Base + ( catch, throwIO, NonTermination (..) + , BlockedIndefinitelyOnMVar (..) ) + +-- | Allow the result of an 'ST' computation to be used (lazily) +-- inside the computation. +-- +-- Note that if @f@ is strict, @'fixST' f = _|_@. +fixST :: (a -> ST s a) -> ST s a +-- See Note [fixST] +fixST k = unsafeIOToST $ do + m <- newEmptyMVar + ans <- unsafeDupableInterleaveIO + (readMVar m `catch` \BlockedIndefinitelyOnMVar -> + throwIO NonTermination) + result <- unsafeSTToIO (k ans) + putMVar m result + return result + +{- 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 the +result was demanded strictly, but we thought that would be okay in the case of +ST. However, that is not the case (see Trac #15349). Notably, the first time +the 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 it +should not. More frighteningly, Arseniy Alekseyev produced a somewhat contrived +example ( 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 do +fixIO. See also the implementation notes for fixIO. Simon Marlow wondered +whether we could get away with an IORef instead of an MVar. I believe we +cannot. The function passed to fixST may spark a parallel computation that +demands the final result. Such a computation should block until the final +result is available. +-} diff --git a/libraries/base/Control/Monad/ST/Lazy/Imp.hs b/libraries/base/Control/Monad/ST/Lazy/Imp.hs index 4f1204b89f..699c81e258 100644 --- a/libraries/base/Control/Monad/ST/Lazy/Imp.hs +++ b/libraries/base/Control/Monad/ST/Lazy/Imp.hs @@ -14,7 +14,7 @@ -- Portability : non-portable (requires universal quantification for runST) -- -- This module presents an identical interface to "Control.Monad.ST", --- except that the monad delays evaluation of state operations until +-- except that the monad delays evaluation of 'ST' operations until -- a value depending on them is required. -- ----------------------------------------------------------------------------- @@ -46,10 +46,10 @@ import qualified GHC.ST as GHC.ST import GHC.Base import qualified Control.Monad.Fail as Fail --- | The lazy state-transformer monad. --- A computation of type @'ST' s a@ transforms an internal state indexed --- by @s@, and returns a value of type @a@. --- The @s@ parameter is either +-- | The lazy @'ST' monad. +-- The ST monad allows for destructive updates, but is escapable (unlike IO). +-- A computation of type @'ST' s a@ returns a value of type @a@, and +-- execute in "thread" @s@. The @s@ parameter is either -- -- * an uninstantiated type variable (inside invocations of 'runST'), or -- @@ -198,13 +198,13 @@ instance Monad (ST s) where instance Fail.MonadFail (ST s) where fail s = errorWithoutStackTrace s --- | Return the value computed by a state transformer computation. +-- | Return the value computed by an 'ST' computation. -- The @forall@ ensures that the internal state used by the 'ST' -- computation is inaccessible to the rest of the program. runST :: (forall s. ST s a) -> a runST (ST st) = runRW# (\s -> case st (S# s) of (r, _) -> r) --- | Allow the result of a state transformer computation to be used (lazily) +-- | Allow the result of an 'ST' computation to be used (lazily) -- inside the computation. -- Note that if @f@ is strict, @'fixST' f = _|_@. fixST :: (a -> ST s a) -> ST s a @@ -243,7 +243,7 @@ lazyToStrictST :: ST s a -> ST.ST s a lazyToStrictST (ST m) = GHC.ST.ST $ \s -> case (m (S# s)) of (a, S# s') -> (# s', a #) --- | A monad transformer embedding lazy state transformers in the 'IO' +-- | A monad transformer embedding lazy 'ST' in the 'IO' -- monad. The 'RealWorld' parameter indicates that the internal state -- used by the 'ST' computation is a special one supplied by the 'IO' -- monad, and thus distinct from those used by invocations of 'runST'. diff --git a/libraries/base/Control/Monad/ST/Lazy/Safe.hs b/libraries/base/Control/Monad/ST/Lazy/Safe.hs index 9f8e60686f..05aaae7523 100644 --- a/libraries/base/Control/Monad/ST/Lazy/Safe.hs +++ b/libraries/base/Control/Monad/ST/Lazy/Safe.hs @@ -11,7 +11,7 @@ -- Portability : non-portable (requires universal quantification for runST) -- -- This module presents an identical interface to "Control.Monad.ST", --- except that the monad delays evaluation of state operations until +-- except that the monad delays evaluation of 'ST' operations until -- a value depending on them is required. -- -- Safe API only. diff --git a/libraries/base/Control/Monad/ST/Lazy/Unsafe.hs b/libraries/base/Control/Monad/ST/Lazy/Unsafe.hs index 4a1b8c79a6..be31c93c24 100644 --- a/libraries/base/Control/Monad/ST/Lazy/Unsafe.hs +++ b/libraries/base/Control/Monad/ST/Lazy/Unsafe.hs @@ -11,7 +11,7 @@ -- Portability : non-portable (requires universal quantification for runST) -- -- This module presents an identical interface to "Control.Monad.ST", --- except that the monad delays evaluation of state operations until +-- except that the monad delays evaluation of 'ST' operations until -- a value depending on them is required. -- -- Unsafe API. diff --git a/libraries/base/Control/Monad/Zip.hs b/libraries/base/Control/Monad/Zip.hs index 5b670085d4..beef913119 100644 --- a/libraries/base/Control/Monad/Zip.hs +++ b/libraries/base/Control/Monad/Zip.hs @@ -21,7 +21,9 @@ module Control.Monad.Zip where import Control.Monad (liftM, liftM2) import Data.Functor.Identity import Data.Monoid +import Data.Ord ( Down(..) ) import Data.Proxy +import qualified Data.List.NonEmpty as NE import GHC.Generics -- | `MonadZip` type class. Minimal definition: `mzip` or `mzipWith` @@ -59,6 +61,12 @@ instance MonadZip [] where mzipWith = zipWith munzip = unzip +-- | @since 4.9.0.0 +instance MonadZip NE.NonEmpty where + mzip = NE.zip + mzipWith = NE.zipWith + munzip = NE.unzip + -- | @since 4.8.0.0 instance MonadZip Identity where mzipWith = liftM2 @@ -117,3 +125,9 @@ instance MonadZip f => MonadZip (M1 i c f) where -- | @since 4.9.0.0 instance (MonadZip f, MonadZip g) => MonadZip (f :*: g) where mzipWith f (x1 :*: y1) (x2 :*: y2) = mzipWith f x1 x2 :*: mzipWith f y1 y2 + +-- instances for Data.Ord + +-- | @since 4.12.0.0 +instance MonadZip Down where + mzipWith = liftM2 |