module Data.List.Safe where

import Data.Bifunctor (first)


-- | Analogous to 'Data.List.last', but returns 'Nothing' on an empty list, instead of throwing an error.
safeLast :: [a] -> Maybe a
safeLast :: forall a. [a] -> Maybe a
safeLast [] = forall a. Maybe a
Nothing
safeLast [a]
l  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
last [a]
l

-- | Analogous to `Data.List.head`, but returns 'Nothing' in case of an empty list.
safeHead :: [a] -> Maybe a
safeHead :: forall a. [a] -> Maybe a
safeHead []      = forall a. Maybe a
Nothing
safeHead (a
x : [a]
_) = forall a. a -> Maybe a
Just a
x

-- | Analogous tu 'Data.List.!!', but does not throw an error on missing index.
safeIndex :: Int -> [a] -> Maybe a
safeIndex :: forall a. Int -> [a] -> Maybe a
safeIndex Int
_ []       = forall a. Maybe a
Nothing
safeIndex Int
0 (a
x : [a]
_)  = forall a. a -> Maybe a
Just a
x
safeIndex Int
n (a
_ : [a]
xs)
  | Int
n forall a. Ord a => a -> a -> Bool
< Int
0            = forall a. Maybe a
Nothing
  | Bool
otherwise        = forall a. Int -> [a] -> Maybe a
safeIndex (Int
n forall a. Num a => a -> a -> a
- Int
1) [a]
xs

-- | Safely deconstructs a list from the end.
--
--   More efficient than @(init x, last x)@
safeUnsnoc :: [a] -> Maybe ([a], a)
safeUnsnoc :: forall a. [a] -> Maybe ([a], a)
safeUnsnoc []       = forall a. Maybe a
Nothing
safeUnsnoc [a
x]      = forall a. a -> Maybe a
Just ([], a
x)
safeUnsnoc (a
x : [a]
xs) = forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (a
x forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. [a] -> Maybe ([a], a)
safeUnsnoc [a]
xs

-- | Safely deconstructs a list from the beginning, returning 'Nothing' if the list is empty.
safeUncons :: [a] -> Maybe (a, [a])
safeUncons :: forall a. [a] -> Maybe (a, [a])
safeUncons []       = forall a. Maybe a
Nothing
safeUncons (a
x : [a]
xs) = forall a. a -> Maybe a
Just (a
x, [a]
xs)