{-# 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 :: (a -> Bool) -> (a -> b) -> a -> Maybe b
liftMay test :: a -> Bool
test f :: a -> b
f val :: 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 :: [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 (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall a. [a] -> a
head

headDef :: a -> [a] -> a
headDef :: a -> [a] -> a
headDef def :: 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 :: [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 (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> [a]
forall a. [a] -> [a]
init

initDef :: [a] -> [a] -> [a]
initDef :: [a] -> [a] -> [a]
initDef def :: [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 :: [a] -> [a]
initSafe = [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
initDef []

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

tailMay :: [a] -> Maybe [a]
tailMay :: [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 (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> [a]
forall a. [a] -> [a]
tail

tailDef :: [a] -> [a] -> [a]
tailDef :: [a] -> [a] -> [a]
tailDef def :: [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 :: [a] -> [a]
tailSafe = [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
tailDef []

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

lastMay :: [a] -> Maybe a
lastMay :: [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 (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall a. [a] -> a
last

lastDef :: a -> [a] -> a
lastDef :: a -> [a] -> a
lastDef def :: 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 :: [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 (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum
maximumMay :: [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 (t :: * -> *) a. Foldable t => t a -> Bool
null [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum

minimumDef, maximumDef :: Ord a => a -> [a] -> a
minimumDef :: a -> [a] -> a
minimumDef def :: 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 :: a -> [a] -> a
maximumDef def :: 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 :: (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 (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 (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1

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

foldl1May :: (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 (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 (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1
foldl1May' :: (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 (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
foldl1'

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

at_ :: [a] -> Int -> Either [Char] a
at_ :: [a] -> Int -> Either [Char] a
at_ ys :: [a]
ys o :: Int
o
  | Int
o Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = [Char] -> Either [Char] a
forall a b. a -> Either a b
Left ("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 0 (x :: b
x:_) = b -> Either [Char] b
forall a b. b -> Either a b
Right b
x
    f i :: Int
i (_:xs :: [b]
xs) = Int -> [b] -> Either [Char] b
f (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-1) [b]
xs
    f i :: Int
i [] = [Char] -> Either [Char] b
forall a b. a -> Either a b
Left ("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]
++ ", 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 :: [a] -> Int -> Maybe a
atMay xs :: [a]
xs i :: Int
i = case [a]
xs [a] -> Int -> Either [Char] a
forall a. [a] -> Int -> Either [Char] a
`at_` Int
i of
  Left _  -> Maybe a
forall a. Maybe a
Nothing
  Right val :: a
val -> a -> Maybe a
forall a. a -> Maybe a
Just a
val

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