{-# LANGUAGE CPP #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Protolude.Safe (
    headMay
  , headDef
  , initMay
  , initDef
  , initSafe
  , tailMay
  , tailDef
  , tailSafe
  , lastDef
  , lastMay
  , foldr1May
  , foldl1May
  , foldl1May'
  , maximumMay
  , minimumMay
  , maximumDef
  , minimumDef
  , atMay
  , atDef
) where


import Data.Ord (Ord, (<))
import Data.Int (Int)
import Data.Char (Char)
import Data.Bool (Bool, otherwise)
import Data.Maybe (Maybe(Nothing, Just), fromMaybe)
import Data.Either (Either(Left, Right))
import Data.Function ((.))
import Data.List (null, head, last, tail, init, maximum, minimum, foldr1, foldl1, foldl1', (++))

import GHC.Num ((-))
import GHC.Show (show)

liftMay :: (a -> Bool) -> (a -> b) -> (a -> Maybe b)
liftMay :: forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay a -> Bool
test a -> b
f a
val = if a -> Bool
test a
val then Maybe b
forall a. Maybe a
Nothing else b -> Maybe b
forall a. a -> Maybe a
Just (a -> b
f a
val)

-------------------------------------------------------------------------------
-- Head
-------------------------------------------------------------------------------

headMay :: [a] -> Maybe a
headMay :: forall a. [a] -> Maybe a
headMay = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall a. HasCallStack => [a] -> a
head

headDef :: a -> [a] -> a
headDef :: forall a. a -> [a] -> a
headDef a
def = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
def (Maybe a -> a) -> ([a] -> Maybe a) -> [a] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Maybe a
forall a. [a] -> Maybe a
headMay

-------------------------------------------------------------------------------
-- Init
-------------------------------------------------------------------------------

initMay :: [a] -> Maybe [a]
initMay :: forall a. [a] -> Maybe [a]
initMay = ([a] -> Bool) -> ([a] -> [a]) -> [a] -> Maybe [a]
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> [a]
forall a. HasCallStack => [a] -> [a]
init

initDef :: [a] -> [a] -> [a]
initDef :: forall a. [a] -> [a] -> [a]
initDef [a]
def = [a] -> Maybe [a] -> [a]
forall a. a -> Maybe a -> a
fromMaybe [a]
def (Maybe [a] -> [a]) -> ([a] -> Maybe [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Maybe [a]
forall a. [a] -> Maybe [a]
initMay

initSafe :: [a] -> [a]
initSafe :: forall a. [a] -> [a]
initSafe = [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
initDef []

-------------------------------------------------------------------------------
-- Tail
-------------------------------------------------------------------------------

tailMay :: [a] -> Maybe [a]
tailMay :: forall a. [a] -> Maybe [a]
tailMay = ([a] -> Bool) -> ([a] -> [a]) -> [a] -> Maybe [a]
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> [a]
forall a. HasCallStack => [a] -> [a]
tail

tailDef :: [a] -> [a] -> [a]
tailDef :: forall a. [a] -> [a] -> [a]
tailDef [a]
def = [a] -> Maybe [a] -> [a]
forall a. a -> Maybe a -> a
fromMaybe [a]
def (Maybe [a] -> [a]) -> ([a] -> Maybe [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Maybe [a]
forall a. [a] -> Maybe [a]
tailMay

tailSafe :: [a] -> [a]
tailSafe :: forall a. [a] -> [a]
tailSafe = [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
tailDef []

-------------------------------------------------------------------------------
-- Last
-------------------------------------------------------------------------------

lastMay :: [a] -> Maybe a
lastMay :: forall a. [a] -> Maybe a
lastMay = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall a. HasCallStack => [a] -> a
last

lastDef :: a -> [a] -> a
lastDef :: forall a. a -> [a] -> a
lastDef a
def = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
def (Maybe a -> a) -> ([a] -> Maybe a) -> [a] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Maybe a
forall a. [a] -> Maybe a
lastMay

-------------------------------------------------------------------------------
-- Maximum
-------------------------------------------------------------------------------

minimumMay, maximumMay :: Ord a => [a] -> Maybe a
minimumMay :: forall a. Ord a => [a] -> Maybe a
minimumMay = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum
maximumMay :: forall a. Ord a => [a] -> Maybe a
maximumMay = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum

minimumDef, maximumDef :: Ord a => a -> [a] -> a
minimumDef :: forall a. Ord a => a -> [a] -> a
minimumDef a
def = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
def (Maybe a -> a) -> ([a] -> Maybe a) -> [a] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Maybe a
forall a. Ord a => [a] -> Maybe a
minimumMay
maximumDef :: forall a. Ord a => a -> [a] -> a
maximumDef a
def = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
def (Maybe a -> a) -> ([a] -> Maybe a) -> [a] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Maybe a
forall a. Ord a => [a] -> Maybe a
maximumMay

-------------------------------------------------------------------------------
-- Foldr
-------------------------------------------------------------------------------

foldr1May, foldl1May, foldl1May' :: (a -> a -> a) -> [a] -> Maybe a
foldr1May :: forall a. (a -> a -> a) -> [a] -> Maybe a
foldr1May = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (([a] -> a) -> [a] -> Maybe a)
-> ((a -> a -> a) -> [a] -> a) -> (a -> a -> a) -> [a] -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a) -> [a] -> a
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1

-------------------------------------------------------------------------------
-- Foldl
-------------------------------------------------------------------------------

foldl1May :: forall a. (a -> a -> a) -> [a] -> Maybe a
foldl1May = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (([a] -> a) -> [a] -> Maybe a)
-> ((a -> a -> a) -> [a] -> a) -> (a -> a -> a) -> [a] -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a) -> [a] -> a
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1
foldl1May' :: forall a. (a -> a -> a) -> [a] -> Maybe a
foldl1May' = ([a] -> Bool) -> ([a] -> a) -> [a] -> Maybe a
forall a b. (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (([a] -> a) -> [a] -> Maybe a)
-> ((a -> a -> a) -> [a] -> a) -> (a -> a -> a) -> [a] -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a) -> [a] -> a
forall a. HasCallStack => (a -> a -> a) -> [a] -> a
foldl1'

-------------------------------------------------------------------------------
-- At
-------------------------------------------------------------------------------

at_ :: [a] -> Int -> Either [Char] a
at_ :: forall a. [a] -> Int -> Either [Char] a
at_ [a]
ys Int
o
  | Int
o Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = [Char] -> Either [Char] a
forall a b. a -> Either a b
Left ([Char]
"index must not be negative, index=" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
o)
  | Bool
otherwise = Int -> [a] -> Either [Char] a
forall {b}. Int -> [b] -> Either [Char] b
f Int
o [a]
ys
  where
    f :: Int -> [b] -> Either [Char] b
f Int
0 (b
x:[b]
_) = b -> Either [Char] b
forall a b. b -> Either a b
Right b
x
    f Int
i (b
_:[b]
xs) = Int -> [b] -> Either [Char] b
f (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) [b]
xs
    f Int
i [] = [Char] -> Either [Char] b
forall a b. a -> Either a b
Left ([Char]
"index too large, index=" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
o [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
", length=" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show (Int
oInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
i))

atMay :: [a] -> Int -> Maybe a
atMay :: forall a. [a] -> Int -> Maybe a
atMay [a]
xs Int
i = case [a]
xs [a] -> Int -> Either [Char] a
forall a. [a] -> Int -> Either [Char] a
`at_` Int
i of
  Left [Char]
_  -> Maybe a
forall a. Maybe a
Nothing
  Right a
val -> a -> Maybe a
forall a. a -> Maybe a
Just a
val

atDef :: a -> [a] -> Int -> a
atDef :: forall a. a -> [a] -> Int -> a
atDef a
def [a]
xs Int
i = case [a]
xs [a] -> Int -> Either [Char] a
forall a. [a] -> Int -> Either [Char] a
`at_` Int
i of
  Left [Char]
_  -> a
def
  Right a
val -> a
val