diff options
author | Tom Sydney Kerckhove <syd@cs-syd.eu> | 2021-03-09 09:24:05 +0100 |
---|---|---|
committer | Hécate Moonlight <kleidukos@crypto-keupone.eu> | 2021-10-15 06:51:18 +0000 |
commit | 7a8171bc9db792b19a2ee4dda9e019de5e24ebe0 (patch) | |
tree | 711cd55fa9ca0dc33160b3074dccda9a73dbbbc0 | |
parent | 481e6b546cdbcb646086cd66f22f588c47e66151 (diff) | |
download | haskell-7a8171bc9db792b19a2ee4dda9e019de5e24ebe0.tar.gz |
Insert warnings in the documentation of dangerous functions
-rw-r--r-- | libraries/base/Data/Foldable.hs | 11 | ||||
-rw-r--r-- | libraries/base/Data/Maybe.hs | 1 | ||||
-rw-r--r-- | libraries/base/GHC/Base.hs | 3 | ||||
-rw-r--r-- | libraries/base/GHC/Conc/Sync.hs | 5 | ||||
-rw-r--r-- | libraries/base/GHC/Exception.hs | 3 | ||||
-rw-r--r-- | libraries/base/GHC/IO/Unsafe.hs | 4 | ||||
-rw-r--r-- | libraries/base/GHC/List.hs | 16 | ||||
-rw-r--r-- | libraries/base/GHC/Real.hs | 35 |
8 files changed, 76 insertions, 2 deletions
diff --git a/libraries/base/Data/Foldable.hs b/libraries/base/Data/Foldable.hs index 21fe7cc72d..24bf13566a 100644 --- a/libraries/base/Data/Foldable.hs +++ b/libraries/base/Data/Foldable.hs @@ -375,6 +375,7 @@ class Foldable t where -- >>> foldl (\a _ -> a) 0 $ repeat 1 -- * Hangs forever * -- + -- WARNING: When it comes to lists, you always want to use either 'foldl'' or 'foldr' instead. foldl :: (b -> a -> b) -> b -> t a -> b foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z -- There's no point mucking around with coercions here, @@ -614,6 +615,8 @@ class Foldable t where -- >>> maximum Nothing -- *** Exception: maximum: empty structure -- + -- WARNING: This function is partial for possibly-empty structures like lists. + -- -- @since 4.8.0.0 maximum :: forall a . Ord a => t a -> a maximum = fromMaybe (errorWithoutStackTrace "maximum: empty structure") . @@ -640,6 +643,8 @@ class Foldable t where -- >>> minimum Nothing -- *** Exception: minimum: empty structure -- + -- WARNING: This function is partial for possibly-empty structures like lists. + -- -- @since 4.8.0.0 minimum :: forall a . Ord a => t a -> a minimum = fromMaybe (errorWithoutStackTrace "minimum: empty structure") . @@ -1192,6 +1197,8 @@ msum = asum -- >>> concat [[1, 2, 3], [4, 5], [6], []] -- [1,2,3,4,5,6] -- +-- WARNING: This function takes O(n^2) time in the total number of elements +-- when the 't' is '[]'. concat :: Foldable t => t [a] -> [a] concat xs = build (\c n -> foldr (\x y -> foldr c y x) n xs) {-# INLINE concat #-} @@ -1325,6 +1332,8 @@ all p = getAll #. foldMap (All #. p) -- -- >>> maximumBy (compare `on` length) ["Hello", "World", "!", "Longest", "bar"] -- "Longest" +-- +-- WARNING: This function is partial for possibly-empty structures like lists. -- See Note [maximumBy/minimumBy space usage] maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a @@ -1347,6 +1356,8 @@ maximumBy cmp = fromMaybe (errorWithoutStackTrace "maximumBy: empty structure") -- -- >>> minimumBy (compare `on` length) ["Hello", "World", "!", "Longest", "bar"] -- "!" +-- +-- WARNING: This function is partial for possibly-empty structures like lists. -- See Note [maximumBy/minimumBy space usage] minimumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a diff --git a/libraries/base/Data/Maybe.hs b/libraries/base/Data/Maybe.hs index acce0bef52..b2b7b0c06d 100644 --- a/libraries/base/Data/Maybe.hs +++ b/libraries/base/Data/Maybe.hs @@ -145,6 +145,7 @@ isNothing _ = False -- *** Exception: Maybe.fromJust: Nothing -- ... -- +-- WARNING: This function is partial. You can use case-matching instead. fromJust :: HasCallStack => Maybe a -> a fromJust Nothing = error "Maybe.fromJust: Nothing" -- yuck fromJust (Just x) = x diff --git a/libraries/base/GHC/Base.hs b/libraries/base/GHC/Base.hs index b80fa3d349..e670e42ee8 100644 --- a/libraries/base/GHC/Base.hs +++ b/libraries/base/GHC/Base.hs @@ -1379,6 +1379,9 @@ The rules for map work like this. -- > [x1, ..., xm] ++ [y1, ...] == [x1, ..., xm, y1, ...] -- -- If the first list is not finite, the result is the first list. +-- +-- WARNING: This function takes linear time in the number of elements of the +-- first list. (++) :: [a] -> [a] -> [a] {-# NOINLINE [1] (++) #-} -- We want the RULE to fire first. diff --git a/libraries/base/GHC/Conc/Sync.hs b/libraries/base/GHC/Conc/Sync.hs index b05fe06f4f..d5fb4868df 100644 --- a/libraries/base/GHC/Conc/Sync.hs +++ b/libraries/base/GHC/Conc/Sync.hs @@ -260,6 +260,11 @@ The newly created thread has an exception handler that discards the exceptions 'BlockedIndefinitelyOnMVar', 'BlockedIndefinitelyOnSTM', and 'ThreadKilled', and passes all other exceptions to the uncaught exception handler. + +WARNING: Exceptions in the new thread will not be rethrown in the thread that +created it. This means that you might be completely unaware of the problem +if/when this happens. You may want to use the +<hackage.haskell.org/package/async async> library instead. -} forkIO :: IO () -> IO ThreadId forkIO action = IO $ \ s -> diff --git a/libraries/base/GHC/Exception.hs b/libraries/base/GHC/Exception.hs index c9ba038182..a2a457891a 100644 --- a/libraries/base/GHC/Exception.hs +++ b/libraries/base/GHC/Exception.hs @@ -45,6 +45,9 @@ import GHC.Exception.Type -- | Throw an exception. Exceptions may be thrown from purely -- functional code, but may only be caught within the 'IO' monad. +-- +-- WARNING: You may want to use 'throwIO' instead so that your pure code +-- stays exception-free. throw :: forall (r :: RuntimeRep). forall (a :: TYPE r). forall e. Exception e => e -> a throw e = raise# (toException e) diff --git a/libraries/base/GHC/IO/Unsafe.hs b/libraries/base/GHC/IO/Unsafe.hs index 5284dcf887..e6c43e920c 100644 --- a/libraries/base/GHC/IO/Unsafe.hs +++ b/libraries/base/GHC/IO/Unsafe.hs @@ -117,6 +117,10 @@ monadic use of references. There is no easy way to make it impossible once you use 'unsafePerformIO'. Indeed, it is possible to write @coerce :: a -> b@ with the help of 'unsafePerformIO'. So be careful! + +WARNING: If you're looking for "a way to get a 'String' from an 'IO String'", +then 'unsafePerformIO' is not the way to go. Learn about do-notation and the +@<-@ syntax element before you proceed. -} unsafePerformIO :: IO a -> a unsafePerformIO m = unsafeDupablePerformIO (noDuplicate >> m) diff --git a/libraries/base/GHC/List.hs b/libraries/base/GHC/List.hs index 658cd2c367..1348d5215f 100644 --- a/libraries/base/GHC/List.hs +++ b/libraries/base/GHC/List.hs @@ -64,6 +64,9 @@ infix 4 `elem`, `notElem` -- 1 -- >>> head [] -- *** Exception: Prelude.head: empty list +-- +-- WARNING: This function is partial. You can use case-matching, 'uncons' or +-- 'listToMaybe' instead. head :: [a] -> a head (x:_) = x head [] = badHead @@ -108,6 +111,9 @@ uncons (x:xs) = Just (x, xs) -- [] -- >>> tail [] -- *** Exception: Prelude.tail: empty list +-- +-- WARNING: This function is partial. You can use case-matching or 'uncons' +-- instead. tail :: [a] -> [a] tail (_:xs) = xs tail [] = errorEmptyList "tail" @@ -121,6 +127,9 @@ tail [] = errorEmptyList "tail" -- * Hangs forever * -- >>> last [] -- *** Exception: Prelude.last: empty list +-- +-- WARNING: This function is partial. You can use 'reverse' with case-matching, +-- 'uncons' or 'listToMaybe' instead. last :: [a] -> a #if defined(USE_REPORT_PRELUDE) last [x] = x @@ -147,6 +156,9 @@ lastError = errorEmptyList "last" -- [] -- >>> init [] -- *** Exception: Prelude.init: empty list +-- +-- WARNING: This function is partial. You can use 'reverse' with case-matching +-- or 'uncons' instead. init :: [a] -> [a] #if defined(USE_REPORT_PRELUDE) init [x] = [] @@ -1296,6 +1308,10 @@ concat = foldr (++) [] -- *** Exception: Prelude.!!: index too large -- >>> ['a', 'b', 'c'] !! (-1) -- *** Exception: Prelude.!!: negative index +-- +-- WARNING: This function is partial. You can use <'atMay' +-- https://hackage.haskell.org/package/safe-0.3.19/docs/Safe.html#v:atMay> +-- instead. (!!) :: [a] -> Int -> a #if defined(USE_REPORT_PRELUDE) xs !! n | n < 0 = errorWithoutStackTrace "Prelude.!!: negative index" diff --git a/libraries/base/GHC/Real.hs b/libraries/base/GHC/Real.hs index a265150171..e71a91007e 100644 --- a/libraries/base/GHC/Real.hs +++ b/libraries/base/GHC/Real.hs @@ -144,20 +144,38 @@ class (Num a, Ord a) => Real a where -- 'abs'. class (Real a, Enum a) => Integral a where -- | integer division truncated toward zero + -- + -- WARNING: This function is partial (because it throws when 0 is passed as + -- the divisor) for all the integer types in @base@. quot :: a -> a -> a -- | integer remainder, satisfying -- -- > (x `quot` y)*y + (x `rem` y) == x + -- + -- WARNING: This function is partial (because it throws when 0 is passed as + -- the divisor) for all the integer types in @base@. rem :: a -> a -> a -- | integer division truncated toward negative infinity + -- + -- WARNING: This function is partial (because it throws when 0 is passed as + -- the divisor) for all the integer types in @base@. div :: a -> a -> a -- | integer modulus, satisfying -- -- > (x `div` y)*y + (x `mod` y) == x + -- + -- WARNING: This function is partial (because it throws when 0 is passed as + -- the divisor) for all the integer types in @base@. mod :: a -> a -> a -- | simultaneous 'quot' and 'rem' + -- + -- WARNING: This function is partial (because it throws when 0 is passed as + -- the divisor) for all the integer types in @base@. quotRem :: a -> a -> (a,a) -- | simultaneous 'div' and 'mod' + -- + -- WARNING: This function is partial (because it throws when 0 is passed as + -- the divisor) for all the integer types in @base@. divMod :: a -> a -> (a,a) -- | conversion to 'Integer' toInteger :: a -> Integer @@ -575,7 +593,10 @@ instance (Integral a) => Enum (Ratio a) where -- Coercions -------------------------------------------------------------- --- | general coercion from integral types +-- | General coercion from 'Integral' types. +-- +-- WARNING: This function performs silent truncation if the result type is not +-- at least as big as the argument's type. {-# INLINE fromIntegral #-} -- Inlined to allow built-in rules to match. -- See Note [Optimising conversions between numeric types] @@ -583,7 +604,17 @@ instance (Integral a) => Enum (Ratio a) where fromIntegral :: (Integral a, Num b) => a -> b fromIntegral = fromInteger . toInteger --- | general coercion to fractional types +-- | General coercion to 'Fractional' types. +-- +-- WARNING: This function goes through the 'Rational' type, which does not have values for 'NaN' for example. +-- This means it does not round-trip. +-- +-- For 'Double' it also behaves differently with or without -O0: +-- +-- > Prelude> realToFrac nan -- With -O0 +-- > -Infinity +-- > Prelude> realToFrac nan +-- > NaN realToFrac :: (Real a, Fractional b) => a -> b {-# NOINLINE [1] realToFrac #-} realToFrac = fromRational . toRational |