summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libraries/base/Data/List.hs1
-rw-r--r--libraries/base/Data/OldList.hs1
-rw-r--r--libraries/base/GHC/List.hs35
-rw-r--r--libraries/base/changelog.md2
4 files changed, 34 insertions, 5 deletions
diff --git a/libraries/base/Data/List.hs b/libraries/base/Data/List.hs
index d7a5922031..a81c743357 100644
--- a/libraries/base/Data/List.hs
+++ b/libraries/base/Data/List.hs
@@ -127,6 +127,7 @@ module Data.List
-- | These functions treat a list @xs@ as a indexed collection,
-- with indices ranging from 0 to @'length' xs - 1@.
+ , (!?)
, (!!)
, elemIndex
diff --git a/libraries/base/Data/OldList.hs b/libraries/base/Data/OldList.hs
index 176c72547c..8e610ebba0 100644
--- a/libraries/base/Data/OldList.hs
+++ b/libraries/base/Data/OldList.hs
@@ -127,6 +127,7 @@ module Data.OldList
-- | These functions treat a list @xs@ as a indexed collection,
-- with indices ranging from 0 to @'length' xs - 1@.
+ , (!?)
, (!!)
, elemIndex
diff --git a/libraries/base/GHC/List.hs b/libraries/base/GHC/List.hs
index 658dabe302..4427d1af1b 100644
--- a/libraries/base/GHC/List.hs
+++ b/libraries/base/GHC/List.hs
@@ -31,7 +31,7 @@ module GHC.List (
-- Other functions
foldl1', concat, concatMap,
map, (++), filter, lookup,
- head, last, tail, init, uncons, (!!),
+ head, last, tail, init, uncons, (!?), (!!),
scanl, scanl1, scanl', scanr, scanr1,
iterate, iterate', repeat, replicate, cycle,
take, drop, splitAt, takeWhile, dropWhile, span, break, reverse,
@@ -49,7 +49,7 @@ import GHC.Num (Num(..))
import GHC.Num.Integer (Integer)
import GHC.Stack.Types (HasCallStack)
-infixl 9 !!
+infixl 9 !?, !!
infix 4 `elem`, `notElem`
-- $setup
@@ -1370,9 +1370,10 @@ concat = foldr (++) []
-- >>> ['a', 'b', 'c'] !! (-1)
-- *** Exception: Prelude.!!: negative index
--
--- WARNING: This function is partial. You can use
--- <https://hackage.haskell.org/package/safe/docs/Safe.html#v:atMay atMay>
--- instead.
+-- WARNING: This function is partial, and should only be used if you are
+-- sure that the indexing will not fail. Otherwise, use 'Data.List.!?'.
+--
+-- WARNING: This function takes linear time in the index.
#if defined(USE_REPORT_PRELUDE)
(!!) :: [a] -> Int -> a
xs !! n | n < 0 = errorWithoutStackTrace "Prelude.!!: negative index"
@@ -1401,6 +1402,30 @@ xs !! n
_ -> r (k-1)) tooLarge xs n
#endif
+-- | List index (subscript) operator, starting from 0. Returns 'Nothing'
+-- if the index is out of bounds
+--
+-- >>> ['a', 'b', 'c'] !? 0
+-- Just 'a'
+-- >>> ['a', 'b', 'c'] !? 2
+-- Just 'c'
+-- >>> ['a', 'b', 'c'] !? 3
+-- Nothing
+-- >>> ['a', 'b', 'c'] !? (-1)
+-- Nothing
+--
+-- This is the total variant of the partial '!!' operator.
+--
+-- WARNING: This function takes linear time in the index.
+(!?) :: [a] -> Int -> Maybe a
+
+{-# INLINABLE (!?) #-}
+xs !? n
+ | n < 0 = Nothing
+ | otherwise = foldr (\x r k -> case k of
+ 0 -> Just x
+ _ -> r (k-1)) (const Nothing) xs n
+
--------------------------------------------------------------
-- The zip family
--------------------------------------------------------------
diff --git a/libraries/base/changelog.md b/libraries/base/changelog.md
index 01dd9fe894..51c02c788f 100644
--- a/libraries/base/changelog.md
+++ b/libraries/base/changelog.md
@@ -58,6 +58,8 @@
freeing a `Pool`. (#14762) (#18338)
* `Type.Reflection.Unsafe` is now marked as unsafe.
* Add `Data.Typeable.heqT`, a kind-heterogeneous version of `Data.Typeable.eqT`.
+ * Add `Data.List.!?` per
+ [CLC proposal #110](https://github.com/haskell/core-libraries-committee/issues/110).
## 4.17.0.0 *August 2022*