summaryrefslogtreecommitdiff
path: root/libraries/base/Control
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/Control')
-rw-r--r--libraries/base/Control/Applicative.hs22
-rw-r--r--libraries/base/Control/Arrow.hs4
-rw-r--r--libraries/base/Control/Category.hs9
-rw-r--r--libraries/base/Control/Concurrent.hs18
-rw-r--r--libraries/base/Control/Concurrent/Chan.hs42
-rw-r--r--libraries/base/Control/Concurrent/MVar.hs12
-rw-r--r--libraries/base/Control/Concurrent/QSem.hs2
-rw-r--r--libraries/base/Control/Concurrent/QSemN.hs2
-rw-r--r--libraries/base/Control/Exception.hs19
-rw-r--r--libraries/base/Control/Exception/Base.hs12
-rw-r--r--libraries/base/Control/Monad.hs134
-rw-r--r--libraries/base/Control/Monad/Fail.hs4
-rw-r--r--libraries/base/Control/Monad/Fix.hs28
-rw-r--r--libraries/base/Control/Monad/ST.hs2
-rw-r--r--libraries/base/Control/Monad/ST/Imp.hs58
-rw-r--r--libraries/base/Control/Monad/ST/Lazy/Imp.hs16
-rw-r--r--libraries/base/Control/Monad/ST/Lazy/Safe.hs2
-rw-r--r--libraries/base/Control/Monad/ST/Lazy/Unsafe.hs2
-rw-r--r--libraries/base/Control/Monad/Zip.hs14
19 files changed, 277 insertions, 125 deletions
diff --git a/libraries/base/Control/Applicative.hs b/libraries/base/Control/Applicative.hs
index 559cceda66..5e2fc8ebe6 100644
--- a/libraries/base/Control/Applicative.hs
+++ b/libraries/base/Control/Applicative.hs
@@ -64,7 +64,10 @@ import GHC.Read (Read)
import GHC.Show (Show)
newtype WrappedMonad m a = WrapMonad { unwrapMonad :: m a }
- deriving (Generic, Generic1, Monad)
+ deriving ( Generic -- ^ @since 4.7.0.0
+ , Generic1 -- ^ @since 4.7.0.0
+ , Monad -- ^ @since 4.7.0.0
+ )
-- | @since 2.01
instance Monad m => Functor (WrappedMonad m) where
@@ -82,7 +85,9 @@ instance MonadPlus m => Alternative (WrappedMonad m) where
WrapMonad u <|> WrapMonad v = WrapMonad (u `mplus` v)
newtype WrappedArrow a b c = WrapArrow { unwrapArrow :: a b c }
- deriving (Generic, Generic1)
+ deriving ( Generic -- ^ @since 4.7.0.0
+ , Generic1 -- ^ @since 4.7.0.0
+ )
-- | @since 2.01
instance Arrow a => Functor (WrappedArrow a b) where
@@ -101,13 +106,20 @@ instance (ArrowZero a, ArrowPlus a) => Alternative (WrappedArrow a b) where
-- | Lists, but with an 'Applicative' functor based on zipping.
newtype ZipList a = ZipList { getZipList :: [a] }
- deriving ( Show, Eq, Ord, Read, Functor
- , Foldable, Generic, Generic1)
+ deriving ( Show -- ^ @since 4.7.0.0
+ , Eq -- ^ @since 4.7.0.0
+ , Ord -- ^ @since 4.7.0.0
+ , Read -- ^ @since 4.7.0.0
+ , Functor -- ^ @since 2.01
+ , Foldable -- ^ @since 4.9.0.0
+ , Generic -- ^ @since 4.7.0.0
+ , Generic1 -- ^ @since 4.7.0.0
+ )
-- See Data.Traversable for Traversable instance due to import loops
-- |
-- > f '<$>' 'ZipList' xs1 '<*>' ... '<*>' 'ZipList' xsN
--- = 'ZipList' (zipWithN f xs1 ... xsN)
+-- > = 'ZipList' (zipWithN f xs1 ... xsN)
--
-- where @zipWithN@ refers to the @zipWith@ function of the appropriate arity
-- (@zipWith@, @zipWith3@, @zipWith4@, ...). For example:
diff --git a/libraries/base/Control/Arrow.hs b/libraries/base/Control/Arrow.hs
index 377870c88c..8d910277a2 100644
--- a/libraries/base/Control/Arrow.hs
+++ b/libraries/base/Control/Arrow.hs
@@ -76,7 +76,7 @@ infixr 1 ^<<, <<^
--
-- * @'first' f >>> 'arr' ('id' *** g) = 'arr' ('id' *** g) >>> 'first' f@
--
--- * @'first' ('first' f) >>> 'arr' 'assoc' = 'arr' 'assoc' >>> 'first' f@
+-- * @'first' ('first' f) >>> 'arr' assoc = 'arr' assoc >>> 'first' f@
--
-- where
--
@@ -209,7 +209,7 @@ instance MonadPlus m => ArrowPlus (Kleisli m) where
--
-- * @'left' f >>> 'arr' ('id' +++ g) = 'arr' ('id' +++ g) >>> 'left' f@
--
--- * @'left' ('left' f) >>> 'arr' 'assocsum' = 'arr' 'assocsum' >>> 'left' f@
+-- * @'left' ('left' f) >>> 'arr' assocsum = 'arr' assocsum >>> 'left' f@
--
-- where
--
diff --git a/libraries/base/Control/Category.hs b/libraries/base/Control/Category.hs
index ba92178bae..6407a6f509 100644
--- a/libraries/base/Control/Category.hs
+++ b/libraries/base/Control/Category.hs
@@ -28,8 +28,13 @@ import GHC.Prim (coerce)
infixr 9 .
infixr 1 >>>, <<<
--- | A class for categories.
--- id and (.) must form a monoid.
+-- | A class for categories. Instances should satisfy the laws
+--
+-- @
+-- f '.' 'id' = f -- (right identity)
+-- 'id' '.' f = f -- (left identity)
+-- f '.' (g '.' h) = (f '.' g) '.' h -- (associativity)
+-- @
class Category cat where
-- | the identity morphism
id :: cat a a
diff --git a/libraries/base/Control/Concurrent.hs b/libraries/base/Control/Concurrent.hs
index cc39ddeccf..bd222e2b1e 100644
--- a/libraries/base/Control/Concurrent.hs
+++ b/libraries/base/Control/Concurrent.hs
@@ -121,6 +121,7 @@ import Foreign.C.Types
import Foreign.C
import System.IO
import Data.Functor ( void )
+import Data.Int ( Int64 )
#else
import qualified GHC.Conc
#endif
@@ -406,7 +407,7 @@ threadWaitRead fd
-- fdReady does the right thing, but we have to call it in a
-- separate thread, otherwise threadWaitRead won't be interruptible,
-- and this only works with -threaded.
- | threaded = withThread (waitFd fd 0)
+ | threaded = withThread (waitFd fd False)
| otherwise = case fd of
0 -> do _ <- hWaitForInput stdin (-1)
return ()
@@ -427,7 +428,7 @@ threadWaitRead fd
threadWaitWrite :: Fd -> IO ()
threadWaitWrite fd
#if defined(mingw32_HOST_OS)
- | threaded = withThread (waitFd fd 1)
+ | threaded = withThread (waitFd fd True)
| otherwise = errorWithoutStackTrace "threadWaitWrite requires -threaded on Windows"
#else
= GHC.Conc.threadWaitWrite fd
@@ -443,7 +444,7 @@ threadWaitReadSTM :: Fd -> IO (STM (), IO ())
threadWaitReadSTM fd
#if defined(mingw32_HOST_OS)
| threaded = do v <- newTVarIO Nothing
- mask_ $ void $ forkIO $ do result <- try (waitFd fd 0)
+ mask_ $ void $ forkIO $ do result <- try (waitFd fd False)
atomically (writeTVar v $ Just result)
let waitAction = do result <- readTVar v
case result of
@@ -467,7 +468,7 @@ threadWaitWriteSTM :: Fd -> IO (STM (), IO ())
threadWaitWriteSTM fd
#if defined(mingw32_HOST_OS)
| threaded = do v <- newTVarIO Nothing
- mask_ $ void $ forkIO $ do result <- try (waitFd fd 1)
+ mask_ $ void $ forkIO $ do result <- try (waitFd fd True)
atomically (writeTVar v $ Just result)
let waitAction = do result <- readTVar v
case result of
@@ -493,16 +494,13 @@ withThread io = do
Right a -> return a
Left e -> throwIO (e :: IOException)
-waitFd :: Fd -> CInt -> IO ()
+waitFd :: Fd -> Bool -> IO ()
waitFd fd write = do
throwErrnoIfMinus1_ "fdReady" $
- fdReady (fromIntegral fd) write iNFINITE 0
-
-iNFINITE :: CInt
-iNFINITE = 0xFFFFFFFF -- urgh
+ fdReady (fromIntegral fd) (if write then 1 else 0) (-1) 0
foreign import ccall safe "fdReady"
- fdReady :: CInt -> CInt -> CInt -> CInt -> IO CInt
+ fdReady :: CInt -> CBool -> Int64 -> CBool -> IO CInt
#endif
-- ---------------------------------------------------------------------------
diff --git a/libraries/base/Control/Concurrent/Chan.hs b/libraries/base/Control/Concurrent/Chan.hs
index ebbec7ea99..874e48a1a1 100644
--- a/libraries/base/Control/Concurrent/Chan.hs
+++ b/libraries/base/Control/Concurrent/Chan.hs
@@ -1,13 +1,12 @@
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP #-}
-{-# LANGUAGE StandaloneDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : Control.Concurrent.Chan
-- 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 (concurrency)
@@ -22,7 +21,7 @@
-----------------------------------------------------------------------------
module Control.Concurrent.Chan
- (
+ (
-- * The 'Chan' type
Chan, -- abstract
@@ -31,8 +30,6 @@ module Control.Concurrent.Chan
writeChan,
readChan,
dupChan,
- unGetChan,
- isEmptyChan,
-- * Stream interface
getChanContents,
@@ -53,7 +50,7 @@ import Control.Exception (mask_)
data Chan a
= Chan _UPK_(MVar (Stream a))
_UPK_(MVar (Stream a)) -- Invariant: the Stream a is always an empty MVar
- deriving (Eq)
+ deriving Eq -- ^ @since 4.4.0.0
type Stream a = MVar (ChItem a)
@@ -105,25 +102,16 @@ writeChan (Chan _ writeVar) val = do
-- guarantees of 'MVar's (e.g. threads blocked in this operation are woken up in
-- FIFO order).
--
--- Throws 'BlockedIndefinitelyOnMVar' when the channel is empty and no other
--- thread holds a reference to the channel.
+-- Throws 'Control.Exception.BlockedIndefinitelyOnMVar' when the channel is
+-- empty and no other thread holds a reference to the channel.
readChan :: Chan a -> IO a
readChan (Chan readVar _) = do
- modifyMVarMasked readVar $ \read_end -> do -- Note [modifyMVarMasked]
+ modifyMVar readVar $ \read_end -> do
(ChItem val new_read_end) <- readMVar read_end
-- Use readMVar here, not takeMVar,
-- else dupChan doesn't work
return (new_read_end, val)
--- Note [modifyMVarMasked]
--- This prevents a theoretical deadlock if an asynchronous exception
--- happens during the readMVar while the MVar is empty. In that case
--- the read_end MVar will be left empty, and subsequent readers will
--- deadlock. Using modifyMVarMasked prevents this. The deadlock can
--- be reproduced, but only by expanding readMVar and inserting an
--- artificial yield between its takeMVar and putMVar operations.
-
-
-- |Duplicate a 'Chan': the duplicate channel begins empty, but data written to
-- either channel from then on will be available from both. Hence this creates
-- a kind of broadcast channel, where data written by anyone is seen by
@@ -137,24 +125,6 @@ dupChan (Chan _ writeVar) = do
newReadVar <- newMVar hole
return (Chan newReadVar writeVar)
--- |Put a data item back onto a channel, where it will be the next item read.
-unGetChan :: Chan a -> a -> IO ()
-unGetChan (Chan readVar _) val = do
- new_read_end <- newEmptyMVar
- modifyMVar_ readVar $ \read_end -> do
- putMVar new_read_end (ChItem val read_end)
- return new_read_end
-{-# DEPRECATED unGetChan "if you need this operation, use Control.Concurrent.STM.TChan instead. See <http://ghc.haskell.org/trac/ghc/ticket/4154> for details" #-} -- deprecated in 7.0
-
--- |Returns 'True' if the supplied 'Chan' is empty.
-isEmptyChan :: Chan a -> IO Bool
-isEmptyChan (Chan readVar writeVar) = do
- withMVar readVar $ \r -> do
- w <- readMVar writeVar
- let eq = r == w
- eq `seq` return eq
-{-# DEPRECATED isEmptyChan "if you need this operation, use Control.Concurrent.STM.TChan instead. See <http://ghc.haskell.org/trac/ghc/ticket/4154> for details" #-} -- deprecated in 7.0
-
-- Operators for interfacing with functional streams.
-- |Return a lazy list representing the contents of the supplied
diff --git a/libraries/base/Control/Concurrent/MVar.hs b/libraries/base/Control/Concurrent/MVar.hs
index 393fca89e2..df28fe8406 100644
--- a/libraries/base/Control/Concurrent/MVar.hs
+++ b/libraries/base/Control/Concurrent/MVar.hs
@@ -33,16 +33,16 @@
--
-- === Applicability
--
--- 'MVar's offer more flexibility than 'IORef's, but less flexibility
--- than 'STM'. They are appropriate for building synchronization
+-- 'MVar's offer more flexibility than 'Data.IORef.IORef's, but less flexibility
+-- than 'GHC.Conc.STM'. They are appropriate for building synchronization
-- primitives and performing simple interthread communication; however
-- they are very simple and susceptible to race conditions, deadlocks or
-- uncaught exceptions. Do not use them if you need perform larger
--- atomic operations such as reading from multiple variables: use 'STM'
+-- atomic operations such as reading from multiple variables: use 'GHC.Conc.STM'
-- instead.
--
--- In particular, the "bigger" functions in this module ('readMVar',
--- 'swapMVar', 'withMVar', 'modifyMVar_' and 'modifyMVar') are simply
+-- In particular, the "bigger" functions in this module ('swapMVar',
+-- 'withMVar', 'modifyMVar_' and 'modifyMVar') are simply
-- the composition of a 'takeMVar' followed by a 'putMVar' with
-- exception safety.
-- These only have atomicity guarantees if all other threads
@@ -70,7 +70,7 @@
--
-- 'MVar' operations are always observed to take place in the order
-- they are written in the program, regardless of the memory model of
--- the underlying machine. This is in contrast to 'IORef' operations
+-- the underlying machine. This is in contrast to 'Data.IORef.IORef' operations
-- which may appear out-of-order to another thread in some cases.
--
-- === Example
diff --git a/libraries/base/Control/Concurrent/QSem.hs b/libraries/base/Control/Concurrent/QSem.hs
index 51624e4777..ea396255a4 100644
--- a/libraries/base/Control/Concurrent/QSem.hs
+++ b/libraries/base/Control/Concurrent/QSem.hs
@@ -29,7 +29,7 @@ import Control.Concurrent.MVar ( MVar, newEmptyMVar, takeMVar, tryTakeMVar
import Control.Exception
import Data.Maybe
--- | 'QSem' is a quantity semaphore in which the resource is aqcuired
+-- | 'QSem' is a quantity semaphore in which the resource is acquired
-- and released in units of one. It provides guaranteed FIFO ordering
-- for satisfying blocked `waitQSem` calls.
--
diff --git a/libraries/base/Control/Concurrent/QSemN.hs b/libraries/base/Control/Concurrent/QSemN.hs
index 7686d3f327..b8c9274057 100644
--- a/libraries/base/Control/Concurrent/QSemN.hs
+++ b/libraries/base/Control/Concurrent/QSemN.hs
@@ -31,7 +31,7 @@ import Control.Concurrent.MVar ( MVar, newEmptyMVar, takeMVar, tryTakeMVar
import Control.Exception
import Data.Maybe
--- | 'QSemN' is a quantity semaphore in which the resource is aqcuired
+-- | 'QSemN' is a quantity semaphore in which the resource is acquired
-- and released in units of one. It provides guaranteed FIFO ordering
-- for satisfying blocked `waitQSemN` calls.
--
diff --git a/libraries/base/Control/Exception.hs b/libraries/base/Control/Exception.hs
index 93ba3d5f91..a84005e536 100644
--- a/libraries/base/Control/Exception.hs
+++ b/libraries/base/Control/Exception.hs
@@ -264,7 +264,7 @@ to write something like
> (\e -> handler)
If you need to unmask asynchronous exceptions again in the exception
-handler, 'restore' can be used there too.
+handler, @restore@ can be used there too.
Note that 'try' and friends /do not/ have a similar default, because
there is no exception handler in this case. Don't use 'try' for
@@ -332,21 +332,24 @@ kind of situation:
The following operations are guaranteed not to be interruptible:
- * operations on 'IORef' from "Data.IORef"
+ * operations on 'Data.IORef.IORef' from "Data.IORef"
- * STM transactions that do not use 'retry'
+ * STM transactions that do not use 'GHC.Conc.retry'
* everything from the @Foreign@ modules
- * everything from @Control.Exception@ except for 'throwTo'
+ * everything from "Control.Exception" except for 'throwTo'
- * @tryTakeMVar@, @tryPutMVar@, @isEmptyMVar@
+ * 'Control.Concurrent.MVar.tryTakeMVar', 'Control.Concurrent.MVar.tryPutMVar',
+ 'Control.Concurrent.MVar.isEmptyMVar'
- * @takeMVar@ if the @MVar@ is definitely full, and conversely @putMVar@ if the @MVar@ is definitely empty
+ * 'Control.Concurrent.MVar.takeMVar' if the 'Control.Concurrent.MVar.MVar' is
+ definitely full, and conversely 'Control.Concurrent.MVar.putMVar' if the
+ 'Control.Concurrent.MVar.MVar' is definitely empty
- * @newEmptyMVar@, @newMVar@
+ * 'Control.Concurrent.MVar.newEmptyMVar', 'Control.Concurrent.MVar.newMVar'
- * @forkIO@, @forkIOUnmasked@, @myThreadId@
+ * 'Control.Concurrent.forkIO', 'Control.Concurrent.myThreadId'
-}
diff --git a/libraries/base/Control/Exception/Base.hs b/libraries/base/Control/Exception/Base.hs
index a15cc8ed32..4b5d94ece7 100644
--- a/libraries/base/Control/Exception/Base.hs
+++ b/libraries/base/Control/Exception/Base.hs
@@ -30,6 +30,7 @@ module Control.Exception.Base (
NonTermination(..),
NestedAtomically(..),
BlockedIndefinitelyOnMVar(..),
+ FixIOException (..),
BlockedIndefinitelyOnSTM(..),
AllocationLimitExceeded(..),
CompactionFailed(..),
@@ -92,9 +93,9 @@ module Control.Exception.Base (
finally,
-- * Calls for GHC runtime
- recSelError, recConError, irrefutPatError, runtimeError,
+ recSelError, recConError, runtimeError,
nonExhaustiveGuardsError, patError, noMethodBindingError,
- absentError, typeError,
+ absentError, absentSumFieldError, typeError,
nonTermination, nestedAtomically,
) where
@@ -374,7 +375,7 @@ instance Exception NestedAtomically
-----
-recSelError, recConError, irrefutPatError, runtimeError,
+recSelError, recConError, runtimeError,
nonExhaustiveGuardsError, patError, noMethodBindingError,
absentError, typeError
:: Addr# -> a -- All take a UTF8-encoded C string
@@ -385,7 +386,6 @@ runtimeError s = errorWithoutStackTrace (unpackCStringUtf8# s)
absentError s = errorWithoutStackTrace ("Oops! Entered absent arg " ++ unpackCStringUtf8# s)
nonExhaustiveGuardsError s = throw (PatternMatchFail (untangle s "Non-exhaustive guards in"))
-irrefutPatError s = throw (PatternMatchFail (untangle s "Irrefutable pattern failed for pattern"))
recConError s = throw (RecConError (untangle s "Missing field in record construction"))
noMethodBindingError s = throw (NoMethodError (untangle s "No instance nor default method for class operation"))
patError s = throw (PatternMatchFail (untangle s "Non-exhaustive patterns in"))
@@ -398,3 +398,7 @@ nonTermination = toException NonTermination
-- GHC's RTS calls this
nestedAtomically :: SomeException
nestedAtomically = toException NestedAtomically
+
+-- Introduced by unarise for unused unboxed sum fields
+absentSumFieldError :: a
+absentSumFieldError = absentError " in unboxed sum."#
diff --git a/libraries/base/Control/Monad.hs b/libraries/base/Control/Monad.hs
index 6a474037c0..96d8938101 100644
--- a/libraries/base/Control/Monad.hs
+++ b/libraries/base/Control/Monad.hs
@@ -86,13 +86,52 @@ import GHC.Num ( (-) )
-- -----------------------------------------------------------------------------
-- Functions mandated by the Prelude
--- | @'guard' b@ is @'pure' ()@ if @b@ is 'True',
--- and 'empty' if @b@ is 'False'.
+-- | Conditional failure of 'Alternative' computations. Defined by
+--
+-- @
+-- guard True = 'pure' ()
+-- guard False = 'empty'
+-- @
+--
+-- ==== __Examples__
+--
+-- Common uses of 'guard' include conditionally signaling an error in
+-- an error monad and conditionally rejecting the current choice in an
+-- 'Alternative'-based parser.
+--
+-- As an example of signaling an error in the error monad 'Maybe',
+-- consider a safe division function @safeDiv x y@ that returns
+-- 'Nothing' when the denominator @y@ is zero and @'Just' (x \`div\`
+-- y)@ otherwise. For example:
+--
+-- @
+-- >>> safeDiv 4 0
+-- Nothing
+-- >>> safeDiv 4 2
+-- Just 2
+-- @
+--
+-- A definition of @safeDiv@ using guards, but not 'guard':
+--
+-- @
+-- safeDiv :: Int -> Int -> Maybe Int
+-- safeDiv x y | y /= 0 = Just (x \`div\` y)
+-- | otherwise = Nothing
+-- @
+--
+-- A definition of @safeDiv@ using 'guard' and 'Monad' @do@-notation:
+--
+-- @
+-- safeDiv :: Int -> Int -> Maybe Int
+-- safeDiv x y = do
+-- guard (y /= 0)
+-- return (x \`div\` y)
+-- @
guard :: (Alternative f) => Bool -> f ()
guard True = pure ()
guard False = empty
--- | This generalizes the list-based 'filter' function.
+-- | This generalizes the list-based 'Data.List.filter' function.
{-# INLINE filterM #-}
filterM :: (Applicative m) => (a -> m Bool) -> [a] -> m [a]
@@ -100,11 +139,12 @@ filterM p = foldr (\ x -> liftA2 (\ flg -> if flg then (x:) else id) (p x
infixr 1 <=<, >=>
--- | Left-to-right Kleisli composition of monads.
+-- | Left-to-right composition of Kleisli arrows.
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
f >=> g = \x -> f x >>= g
--- | Right-to-left Kleisli composition of monads. @('>=>')@, with the arguments flipped.
+-- | Right-to-left composition of Kleisli arrows. @('>=>')@, with the arguments
+-- flipped.
--
-- Note how this operator resembles function composition @('.')@:
--
@@ -113,7 +153,30 @@ f >=> g = \x -> f x >>= g
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
(<=<) = flip (>=>)
--- | @'forever' act@ repeats the action infinitely.
+-- | Repeat an action indefinitely.
+--
+-- ==== __Examples__
+--
+-- A common use of 'forever' is to process input from network sockets,
+-- 'System.IO.Handle's, and channels
+-- (e.g. 'Control.Concurrent.MVar.MVar' and
+-- 'Control.Concurrent.Chan.Chan').
+--
+-- For example, here is how we might implement an [echo
+-- server](https://en.wikipedia.org/wiki/Echo_Protocol), using
+-- 'forever' both to listen for client connections on a network socket
+-- and to echo client input on client connection handles:
+--
+-- @
+-- echoServer :: Socket -> IO ()
+-- echoServer socket = 'forever' $ do
+-- client <- accept socket
+-- 'Control.Concurrent.forkFinally' (echo client) (\\_ -> hClose client)
+-- where
+-- echo :: Handle -> IO ()
+-- echo client = 'forever' $
+-- hGetLine client >>= hPutStrLn client
+-- @
forever :: (Applicative f) => f a -> f b
{-# INLINE forever #-}
forever a = let a' = a *> a' in a'
@@ -125,7 +188,7 @@ forever a = let a' = a *> a' in a'
-- | The 'mapAndUnzipM' function maps its first argument over a list, returning
-- the result as a pair of lists. This function is mainly used with complicated
--- data structures or a state-transforming monad.
+-- data structures or a state monad.
mapAndUnzipM :: (Applicative m) => (a -> m (b,c)) -> [a] -> m ([b], [c])
{-# INLINE mapAndUnzipM #-}
mapAndUnzipM f xs = unzip <$> traverse f xs
@@ -140,21 +203,21 @@ zipWithM_ :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m ()
{-# INLINE zipWithM_ #-}
zipWithM_ f xs ys = sequenceA_ (zipWith f xs ys)
-{- | The 'foldM' function is analogous to 'foldl', except that its result is
+{- | The 'foldM' function is analogous to 'Data.Foldable.foldl', except that its result is
encapsulated in a monad. Note that 'foldM' works from left-to-right over
the list arguments. This could be an issue where @('>>')@ and the `folded
function' are not commutative.
-> foldM f a1 [x1, x2, ..., xm]
-
-==
-
-> do
-> a2 <- f a1 x1
-> a3 <- f a2 x2
-> ...
-> f am xm
+> foldM f a1 [x1, x2, ..., xm]
+>
+> ==
+>
+> do
+> a2 <- f a1 x1
+> a3 <- f a2 x2
+> ...
+> f am xm
If right-to-left evaluation is required, the input list should be reversed.
@@ -244,12 +307,25 @@ f <$!> m = do
-- -----------------------------------------------------------------------------
-- Other MonadPlus functions
--- | Direct 'MonadPlus' equivalent of 'filter'
--- @'filter'@ = @(mfilter:: (a -> Bool) -> [a] -> [a]@
--- applicable to any 'MonadPlus', for example
--- @mfilter odd (Just 1) == Just 1@
--- @mfilter odd (Just 2) == Nothing@
-
+-- | Direct 'MonadPlus' equivalent of 'Data.List.filter'.
+--
+-- ==== __Examples__
+--
+-- The 'Data.List.filter' function is just 'mfilter' specialized to
+-- the list monad:
+--
+-- @
+-- 'Data.List.filter' = ( 'mfilter' :: (a -> Bool) -> [a] -> [a] )
+-- @
+--
+-- An example using 'mfilter' with the 'Maybe' monad:
+--
+-- @
+-- >>> mfilter odd (Just 1)
+-- Just 1
+-- >>> mfilter odd (Just 2)
+-- Nothing
+-- @
mfilter :: (MonadPlus m) => (a -> Bool) -> m a -> m a
{-# INLINABLE mfilter #-}
mfilter p ma = do
@@ -264,19 +340,19 @@ The functions in this library use the following naming conventions:
The monad type constructor @m@ is added to function results
(modulo currying) and nowhere else. So, for example,
-> filter :: (a -> Bool) -> [a] -> [a]
-> filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
+> filter :: (a -> Bool) -> [a] -> [a]
+> filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
* A postfix \'@_@\' changes the result type from @(m a)@ to @(m ())@.
Thus, for example:
-> sequence :: Monad m => [m a] -> m [a]
-> sequence_ :: Monad m => [m a] -> m ()
+> sequence :: Monad m => [m a] -> m [a]
+> sequence_ :: Monad m => [m a] -> m ()
* A prefix \'@m@\' generalizes an existing function to a monadic form.
Thus, for example:
-> sum :: Num a => [a] -> a
-> msum :: MonadPlus m => [m a] -> m a
+> filter :: (a -> Bool) -> [a] -> [a]
+> mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a
-}
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