-- |
-- Module      :  Data.SubG
-- Copyright   :  (c) OleksandrZhabenko 2020-2023
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  oleksandr.zhabenko@yahoo.com
--
-- Some extension to the 'F.Foldable' and 'Monoid' classes. Introduces a new class 'InsertLeft' -- the class of types of values that can be inserted from the left
-- to the 'F.Foldable' structure that is simultaneously the data that is also the 'Monoid'
-- instance. For lists as instances of 'InsertLeft' and 'Monoid' just use the basic library
-- functions from GHC.List or Data.List modules where possible.

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, NoImplicitPrelude #-}

module Data.SubG (
  InsertLeft(..)
  , subG
  , takeFromEndG
  , reverseTakeFromEndG
  , dropFromEndG
  , reverseDropFromEndG
  , takeWhile
  , dropWhile
  , span
  , splitAtEndG
  , preAppend
  , safeHeadG
  , safeInitG
  , safeLastG
  , mapG
  , filterG
  , partitionG
  -- * Not recommended for performance reasons, provided if there is no other acceptable possibilities (as fallback placeholders)
  , reverseTakeG
  , takeG
  , reverseDropG
  , dropG
  , splitAtG
  , safeTailG
) where

import GHC.Base
import GHC.Num
import GHC.Real
import Data.Tuple
import qualified Data.Foldable as F
import Data.Monoid

infixr 1 %@, %^

-- | Some extension to the 'F.Foldable' and 'Monoid' classes.
class (F.Foldable t, Eq a, Eq (t a)) => InsertLeft t a where
  (%@) :: a -> t a -> t a  -- infixr 1
  (%^) :: t a -> t (t a) -> t (t a)

instance (Eq a) => InsertLeft [] a where
  %@ :: a -> [a] -> [a]
(%@) = (:)
  %^ :: [a] -> [[a]] -> [[a]]
(%^) = (:)

-- | Inspired by: https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#words
-- and: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Is similar to the 'Prelude.words' but operates on more general
-- structures an allows more control.
subG :: (InsertLeft t a, Monoid (t a), Monoid (t (t a))) => t a -> t a -> t (t a)
subG :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a), Monoid (t (t a))) =>
t a -> t a -> t (t a)
subG t a
whspss t a
xs = if forall (t :: * -> *) a. Foldable t => t a -> Bool
F.null t a
ts then forall a. Monoid a => a
mempty else t a
w forall (t :: * -> *) a. InsertLeft t a => t a -> t (t a) -> t (t a)
%^ forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a), Monoid (t (t a))) =>
t a -> t a -> t (t a)
subG t a
whspss t a
s''
     where ts :: t a
ts = forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> t a
dropWhile (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`F.elem` t a
whspss) t a
xs
           (t a
w, t a
s'') = forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
span (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`F.notElem` t a
whspss) t a
ts

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
dropWhile' :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> (t a, t a)
dropWhile' :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
dropWhile' a -> Bool
p = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {t :: * -> *}.
InsertLeft t a =>
a -> (t a, t a) -> (t a, t a)
f (t a, t a)
v
  where f :: a -> (t a, t a) -> (t a, t a)
f a
x (t a
ys, t a
xs) = (if a -> Bool
p a
x then t a
ys else a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
xs, a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
xs)
        v :: (t a, t a)
v = (forall a. Monoid a => a
mempty,forall a. Monoid a => a
mempty)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
dropWhile :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> t a
dropWhile :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> t a
dropWhile a -> Bool
p = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
dropWhile' a -> Bool
p

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
span :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> (t a, t a)
span :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
span a -> Bool
p = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> ((t a, t a), t a)
span' a -> Bool
p

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
span' :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> ((t a, t a), t a)
span' :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> ((t a, t a), t a)
span' a -> Bool
p = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {t :: * -> *} {t :: * -> *}.
(Monoid (t a), InsertLeft t a, InsertLeft t a) =>
a -> ((t a, t a), t a) -> ((t a, t a), t a)
f ((t a, t a), t a)
v
  where f :: a -> ((t a, t a), t a) -> ((t a, t a), t a)
f a
x ((t a
ys, t a
zs), t a
xs) = (if a -> Bool
p a
x then (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
ys, t a
zs) else (forall a. Monoid a => a
mempty,a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
xs), a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
xs)
        v :: ((t a, t a), t a)
v = ((forall a. Monoid a => a
mempty, forall a. Monoid a => a
mempty), forall a. Monoid a => a
mempty)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
takeWhile :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> t a
takeWhile :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> t a
takeWhile a -> Bool
p = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
takeWhile' a -> Bool
p

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
takeWhile' :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> (t a, t a)
takeWhile' :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
takeWhile' a -> Bool
p = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {t :: * -> *} {t :: * -> *}.
(Monoid (t a), InsertLeft t a, InsertLeft t a) =>
a -> (t a, t a) -> (t a, t a)
f (t a, t a)
v
  where f :: a -> (t a, t a) -> (t a, t a)
f a
x (t a
ys,t a
xs) = (if a -> Bool
p a
x then a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
ys else forall a. Monoid a => a
mempty, a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
xs)
        v :: (t a, t a)
v = (forall a. Monoid a => a
mempty,forall a. Monoid a => a
mempty)

-- | Prepends and appends the given two first arguments to the third one.
preAppend :: (InsertLeft t a, Monoid (t (t a))) => t a -> t (t a) -> t (t a) -> t (t a)
preAppend :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t (t a))) =>
t a -> t (t a) -> t (t a) -> t (t a)
preAppend t a
ts t (t a)
uss t (t a)
tss = forall a. Monoid a => [a] -> a
mconcat [t a
ts forall (t :: * -> *) a. InsertLeft t a => t a -> t (t a) -> t (t a)
%^ t (t a)
tss, t (t a)
uss]
{-# INLINE preAppend #-}

-------------------------------------------------------------------------------------

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Takes the first argument quantity from the right end of the structure preserving the order.
takeFromEndG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
takeFromEndG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
takeFromEndG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {c} {t :: * -> *} {a}.
(Ord c, InsertLeft t a, Num c) =>
a -> (t a, c, c) -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: a -> (t a, c, c) -> (t a, c, c)
f a
x (t a
zs,c
k,c
n)
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
zs,c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (t a
zs,c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Takes the specified quantity from the right end of the structure and then reverses the result.
reverseTakeFromEndG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
reverseTakeFromEndG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
reverseTakeFromEndG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {c} {t :: * -> *} {a}.
(Ord c, Monoid (t a), InsertLeft t a, Num c) =>
a -> (t a, c, c) -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: a -> (t a, c, c) -> (t a, c, c)
f a
x (t a
zs,c
k,c
n)
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (t a
zs forall a. Monoid a => a -> a -> a
`mappend` (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ forall a. Monoid a => a
mempty),c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (t a
zs,c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Is analogous to the taking the specified quantity from the structure and then reversing the result. Uses strict variant of the foldl, so is
-- not suitable for large amounts of data. Not recommended for performance reasons. For lists just
-- use the combination @(reverse . take n)@.
reverseTakeG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
reverseTakeG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
reverseTakeG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall {c} {t :: * -> *} {a}.
(Ord c, InsertLeft t a, Num c) =>
(t a, c, c) -> a -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: (t a, c, c) -> a -> (t a, c, c)
f (t a
zs,c
k,c
n) a
x
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
zs,c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (t a
zs,c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Uses strict variant of the foldl, so is
-- strict and the data must be finite. Not recommended for performance reasons. For lists just use
-- GHC.List.take n.
takeG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
takeG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
takeG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall {c} {t :: * -> *} {a}.
(Ord c, Monoid (t a), InsertLeft t a, Num c) =>
(t a, c, c) -> a -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: (t a, c, c) -> a -> (t a, c, c)
f (t a
zs,c
k,c
n) a
x
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (t a
zs forall a. Monoid a => a -> a -> a
`mappend` (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ forall a. Monoid a => a
mempty),c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (t a
zs,c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Is analogous to the dropping the specified quantity from the structure and then reversing the result. Uses strict variant of the foldl, so is
-- strict and the data must be finite. Not recommended for performance reasons. For lists just 
-- use @ (reverse . drop n) combination.
reverseDropG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
reverseDropG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
reverseDropG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall {c} {t :: * -> *} {a}.
(Ord c, Monoid (t a), Num c, InsertLeft t a) =>
(t a, c, c) -> a -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: (t a, c, c) -> a -> (t a, c, c)
f (t a
zs,c
k,c
n) a
x
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (forall a. Monoid a => a
mempty,c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
zs,c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Drops the first argument quantity from the right end of the structure and returns the result preserving the order.
dropFromEndG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
dropFromEndG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
dropFromEndG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {c} {t :: * -> *} {a}.
(Ord c, Monoid (t a), Num c, InsertLeft t a) =>
a -> (t a, c, c) -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: a -> (t a, c, c) -> (t a, c, c)
f a
x (t a
zs,c
k,c
n)
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (forall a. Monoid a => a
mempty,c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
zs,c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Drops the specified quantity from the right end of the structure and then reverses the result.
reverseDropFromEndG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
reverseDropFromEndG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
reverseDropFromEndG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {c} {t :: * -> *} {a}.
(Ord c, Monoid (t a), Num c, InsertLeft t a) =>
a -> (t a, c, c) -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: a -> (t a, c, c) -> (t a, c, c)
f a
x (t a
zs,c
k,c
n)
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (forall a. Monoid a => a
mempty,c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (t a
zs forall a. Monoid a => a -> a -> a
`mappend` (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ forall a. Monoid a => a
mempty),c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Uses strict variant of the foldl, so is
-- strict and the data must be finite. Not recommended for performance  reasons. For lists just use
-- the GHC.List.drop.
dropG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> t a
dropG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
dropG b
n = (\(t a
xs,b
_,b
_) -> t a
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall {c} {t :: * -> *} {a}.
(Ord c, Monoid (t a), Num c, InsertLeft t a) =>
(t a, c, c) -> a -> (t a, c, c)
f (t a, b, b)
v
 where v :: (t a, b, b)
v = (forall a. Monoid a => a
mempty,b
0,b
n)
       f :: (t a, c, c) -> a -> (t a, c, c)
f (t a
zs,c
k,c
n) a
x
        | c
k forall a. Ord a => a -> a -> Bool
< c
n = (forall a. Monoid a => a
mempty,c
k forall a. Num a => a -> a -> a
+ c
1,c
n)
        | Bool
otherwise = (t a
zs forall a. Monoid a => a -> a -> a
`mappend` (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ forall a. Monoid a => a
mempty),c
k,c
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Uses strict variant of the foldl, so is
-- strict and the data must be finite. Not recommended for performance reasons. For lists just use
-- the GHC.List.splitAt.
splitAtG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> (t a, t a)
splitAtG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> (t a, t a)
splitAtG b
n = (\(t a
x,t a
y,b
_,b
_) -> (t a
x,t a
y)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall {d} {t :: * -> *} {a} {t :: * -> *}.
(Ord d, Monoid (t a), Monoid (t a), Num d, InsertLeft t a,
 InsertLeft t a) =>
(t a, t a, d, d) -> a -> (t a, t a, d, d)
f (t a, t a, b, b)
v
 where v :: (t a, t a, b, b)
v = (forall a. Monoid a => a
mempty,forall a. Monoid a => a
mempty,b
0,b
n)
       f :: (t a, t a, d, d) -> a -> (t a, t a, d, d)
f (t a
zs,t a
ts,d
k,d
n) a
x
        | d
k forall a. Ord a => a -> a -> Bool
< d
n = (t a
zs forall a. Monoid a => a -> a -> a
`mappend` (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ forall a. Monoid a => a
mempty),forall a. Monoid a => a
mempty,d
k forall a. Num a => a -> a -> a
+ d
1,d
n)
        | Bool
otherwise = (t a
zs,t a
ts forall a. Monoid a => a -> a -> a
`mappend` (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ forall a. Monoid a => a
mempty),d
k forall a. Num a => a -> a -> a
+ d
1,d
n)

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Splits the structure starting from the end and preserves the order.
splitAtEndG :: (Integral b, InsertLeft t a, Monoid (t a)) => b -> t a -> (t a, t a)
splitAtEndG :: forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> (t a, t a)
splitAtEndG b
n = (\(t a
x,t a
y,b
_,b
_) -> (t a
y,t a
x)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {d} {t :: * -> *} {a} {t :: * -> *}.
(Ord d, Monoid (t a), Num d, InsertLeft t a, InsertLeft t a) =>
a -> (t a, t a, d, d) -> (t a, t a, d, d)
f (t a, t a, b, b)
v
 where v :: (t a, t a, b, b)
v = (forall a. Monoid a => a
mempty,forall a. Monoid a => a
mempty,b
0,b
n)
       f :: a -> (t a, t a, d, d) -> (t a, t a, d, d)
f a
x (t a
zs,t a
ts,d
k,d
n)
        | d
k forall a. Ord a => a -> a -> Bool
< d
n = (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
zs,forall a. Monoid a => a
mempty,d
k forall a. Num a => a -> a -> a
+ d
1,d
n)
        | Bool
otherwise = (t a
zs,a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
ts,d
k forall a. Num a => a -> a -> a
+ d
1,d
n)

-- | If a structure is empty, just returns 'Nothing'.
safeHeadG :: (F.Foldable t) => t a -> Maybe a
safeHeadG :: forall (t :: * -> *) a. Foldable t => t a -> Maybe a
safeHeadG = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
F.find (forall a b. a -> b -> a
const Bool
True)

-- | If the structure is empty, just returns itself. Uses strict variant of the foldl, so is
-- strict and the data must be finite. Not recommended for performance reasons. For lists just use 
-- Data.List.tail or something equivalent.
safeTailG :: (InsertLeft t a, Monoid (t a)) => t a -> t a
safeTailG :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
t a -> t a
safeTailG = forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
dropG Integer
1

-- | If the structure is empty, just returns itself.
safeInitG :: (InsertLeft t a, Monoid (t a)) => t a -> t a
safeInitG :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
t a -> t a
safeInitG = forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
dropFromEndG Integer
1

-- | If the structure is empty, just returns 'Nothing'.
safeLastG :: (InsertLeft t a, Monoid (t a)) => t a -> Maybe a
safeLastG :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
t a -> Maybe a
safeLastG = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
F.find (forall a b. a -> b -> a
const Bool
True) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> t a
takeFromEndG Integer
1

-----------------------------------------------------------------------------

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Acts similarly to the 'map' function from Prelude.
mapG :: (InsertLeft t b, Monoid (t b)) => (a -> b) -> t a -> t b
mapG :: forall (t :: * -> *) b a.
(InsertLeft t b, Monoid (t b)) =>
(a -> b) -> t a -> t b
mapG a -> b
f = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr (\a
x t b
ys -> a -> b
f a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t b
ys) forall a. Monoid a => a
mempty

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Acts similarly to 'filter' function from Prelude.
filterG :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> t a
filterG :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> t a
filterG a -> Bool
p = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr (\a
x t a
ys -> if a -> Bool
p a
x then a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
ys else t a
ys) forall a. Monoid a => a
mempty

-- | Inspired by: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf. Acts similarly to 'partition' function from Data.List. Practically is a
-- rewritten for more general variants function partition from https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#partition
partitionG :: (InsertLeft t a, Monoid (t a)) => (a -> Bool) -> t a -> (t a, t a)
partitionG :: forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Bool) -> t a -> (t a, t a)
partitionG a -> Bool
p = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr (\a
x (t a
ys,t a
zs) -> if a -> Bool
p a
x then (a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
ys,t a
zs) else (t a
ys,a
x forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ t a
zs)) (forall a. Monoid a => a
mempty,forall a. Monoid a => a
mempty)