packages feed

ranged-list-0.1.2.0: src/Data/List/Range/RangeL.hs

{-# LANGUAGE BlockArguments, LambdaCase, TupleSections #-}
{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}
{-# LANGUAGE DataKinds, KindSignatures, TypeOperators #-}
{-# LANGUAGE GADTs, TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,
	UndecidableInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}

module Data.List.Range.RangeL (
	LengthL,
	-- ** Type
	RangeL(..),
	-- ** PushL
	PushL, (.:..),
	-- ** AddL
	AddL, (++.),
	-- ** LoosenLMin and LoosenLMax
	-- *** loosenL
	loosenL,
	-- *** loosenLMin
	LoosenLMin, loosenLMin,
	-- *** loosenLMax
	LoosenLMax, loosenLMax,
	-- ** Unfoldr
	-- *** class
	Unfoldr,
	-- *** unfoldrRange
	-- **** without monad
	unfoldrRange, unfoldrRangeWithBase, unfoldrRangeWithBaseWithS,
	-- **** with monad
	unfoldrMRange, unfoldrMRangeWithBase,
	-- *** unfoldrRangeMaybe
	-- **** without monad
	unfoldrRangeMaybe, unfoldrRangeMaybeWithBase,
	-- **** with monad
	unfoldrMRangeMaybe, unfoldrMRangeMaybeWithBase,
	-- ** ZipL
	ZipL, zipL, zipWithL, zipWithML ) where

import GHC.TypeNats (Nat, type (+), type (-), type (<=))
import GHC.Exts (IsList(..))
import Control.Arrow (first, second, (***), (&&&))
import Control.Monad.Identity (Identity(..))
import Control.Monad.State (StateL(..))
import Data.Kind (Type)
import Data.Foldable (toList)
import Data.Bool (bool)
import Data.Maybe (isJust, fromMaybe)
import Data.String

type LengthL n = RangeL n n

{-^

The value of @LengthL n a@ is a list which have just @n@ members of type @a@.
You can push and pop an element from left.

>>> :set -XDataKinds
>>> sampleLengthL = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :. NilL :: LengthL 5 Char

-}

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

-- * TYPE
--	+ RANGE LEFT
--	+ INSTANCE FUNCTOR
--	+ INSTANCE FOLDABLE
-- * PUSH
-- * ADD
-- * LOOSEN
-- 	+ LOOSEN LEFT
-- 	+ LOOSEN LEFT MIN
-- 	+ LOOSEN LEFT MAX
-- * UNFOLDR
-- 	+ CLASS
-- 	+ INSTANCE
-- 	+ UNFOLDR RANGE
-- 	+ UNFOLDR RANGE MAYBE
-- * ZIP
--	+ CLASS
--	+ FUNCTION

---------------------------------------------------------------------------
-- TYPE
---------------------------------------------------------------------------

-- RANGE LEFT

data RangeL :: Nat -> Nat -> Type -> Type where
	NilL :: 0 <= m => RangeL 0 m a
	(:..) :: 1 <= m => a -> RangeL 0 (m - 1) a -> RangeL 0 m a
	(:.) :: (1 <= n, 1 <= m) =>
		a -> RangeL (n - 1) (m - 1) a -> RangeL n m a

{-^

The value of @RangeL n m a@ is a list of type @a@ values whose element number is
at minimum @n@, and at maximum @m@.
You can push and pop an element from left.

>>> :set -XDataKinds
>>> sampleRangeL = 'h' :. 'e' :. 'l' :. 'l' :.. 'o' :.. NilL :: RangeL 3 8 Char

-}

infixr 6 :., :..

deriving instance Eq a => Eq (RangeL n m a)
deriving instance Ord a => Ord (RangeL n m a)
deriving instance Show a => Show (RangeL n m a)

-- INSTANCE FUNCTOR

instance Functor (RangeL 0 0) where _ `fmap` NilL = NilL

instance {-# OVERLAPPABLE #-}
	Functor (RangeL 0 (m - 1)) => Functor (RangeL 0 m) where
	fmap f = \case NilL -> NilL; x :.. xs -> f x :.. (f <$> xs)

instance {-# OVERLAPPABLE #-}
	(1 <= n, Functor (RangeL (n - 1) (m - 1))) => Functor (RangeL n m) where
	f `fmap` (x :. xs) = f x :. (f <$> xs)

-- INSTANCE FOLDABLE

instance Foldable (RangeL 0 0) where foldr _ z NilL = z

instance {-# OVERLAPPABLE #-}
	Foldable (RangeL 0 (m - 1)) => Foldable (RangeL 0 m) where
	foldr (-<) z = \case NilL -> z; x :.. xs -> x -< foldr (-<) z xs

instance {-# OVERLAPPABLE #-} (1 <= n, Foldable (RangeL (n - 1) (m - 1))) =>
	Foldable (RangeL n m) where
	foldr (-<) z (x :. xs) = x -< foldr (-<) z xs

-- INSTANCE TRAVERSABLE

instance Traversable (RangeL 0 0) where traverse _ NilL = pure NilL

instance {-# OVERLAPPABLE #-}
	Traversable (RangeL 0 (m - 1)) => Traversable (RangeL 0 m) where
	traverse f = \case
		NilL -> pure NilL; x :.. xs -> (:..) <$> f x <*> traverse f xs

instance {-# OVERLAPPABLE #-} (1 <= n, Traversable (RangeL (n - 1) (m - 1))) =>
	Traversable (RangeL n m) where
	traverse f (x :. xs) = (:.) <$> f x <*> traverse f xs

-- INSTANCE APPLICATIVE

instance Applicative (LengthL 0) where pure _ = NilL; _ <*> _ = NilL

instance {-# OVERLAPPABLE #-} (Functor (RangeL 0 m), Applicative (RangeL 0 (m - 1)), Unfoldr 0 0 m) => Applicative (RangeL 0 m) where
	pure = unfoldrRange (const True) (\x -> (x, x))
	NilL <*> _ = NilL
	_ <*> NilL = NilL
	f :.. fs <*> x :.. xs = f x :.. (fs <*> xs)

instance {-# OVERLAPPABLE #-} (1 <= n, Functor (RangeL n m), Applicative (RangeL (n - 1) (m - 1)), Unfoldr 0 n m) => Applicative (RangeL n m) where
	pure = unfoldrRange (const True) (\x -> (x, x))
	f :. fs <*> x :. xs = f x :. (fs <*> xs)

instance Applicative (LengthL 0) => Monad (LengthL 0) where
	NilL >>= _ = NilL

instance {-# OVERLAPPABLE #-} (1 <= n, Applicative (LengthL n), Monad (LengthL (n - 1))) => Monad (LengthL n) where
	x :. xs >>= f = y :. (xs >>= \z -> case f z of _ :. zs -> zs)
		where y :. _ = f x

-- INSTANCE ISSTRING

instance Unfoldr 0 n m => IsString (RangeL n m Char) where
	fromString s = fromMaybe (error $ "The string " ++ show s ++ " is not within range.")
		$ unfoldrRangeMaybe (\case "" -> Nothing; c : cs -> Just (c, cs)) s

instance (Foldable (RangeL n m), Unfoldr 0 n m) => IsList (RangeL n m a) where
	type Item (RangeL n m a) = a
	fromList lst = fromMaybe (error $ "The list is not within range.")
		$ unfoldrRangeMaybe (\case [] -> Nothing; x : xs -> Just (x, xs)) lst
	toList = Data.Foldable.toList

---------------------------------------------------------------------------
-- PUSH
---------------------------------------------------------------------------

infixr 5 .:..

class PushL n m where
	(.:..) :: a -> RangeL n m a -> RangeL n (m + 1) a

	{-^

	To push an optional element.

	>>> :set -XDataKinds
	>>> samplePushL = 'e' :. 'l' :. 'l' :. 'o' :.. NilL :: RangeL 3 7 Char
	>>> 'h' .:.. samplePushL
	'h' :. ('e' :. ('l' :. ('l' :.. ('o' :.. NilL))))
	>>> :type 'h' .:.. samplePushL
	'h' .:.. samplePushL :: RangeL 3 8 Char

	-}

instance PushL 0 m where
	(.:..) x = \case NilL -> x :.. NilL; xs@(_ :.. _) -> x :.. xs

instance {-# OVERLAPPABLE #-} (1 <= n, PushL (n - 1) (m - 1)) => PushL n m where
	x .:.. y :. ys = x :. (y .:.. ys)

---------------------------------------------------------------------------
-- ADD
---------------------------------------------------------------------------

infixr 5 ++.

class AddL n m v w where
	(++.) :: RangeL n m a -> RangeL v w a -> RangeL (n + v) (m + w) a

	{-^

	To concatenate two lists
	whose types are @RangeL n m a@ and @RangeL v w a@.

	>>> :set -XDataKinds
	>>> sampleAddL1 = 'f' :. 'o' :. 'o' :.. NilL :: RangeL 2 5 Char
	>>> sampleAddL2 = 'b' :. 'a' :.. 'r' :.. NilL :: RangeL 1 6 Char
	>>> sampleAddL1 ++. sampleAddL2
	'f' :. ('o' :. ('o' :. ('b' :.. ('a' :.. ('r' :.. NilL)))))
	>>> :type sampleAddL1 ++. sampleAddL2
	sampleAddL1 ++. sampleAddL2 :: RangeL 3 11 Char

	-}

instance AddL 0 0 v w where NilL ++. ys = ys

instance {-# OVERLAPPABLE #-}
	(PushL v (m + w - 1), AddL 0 (m - 1) v w, LoosenLMax v w (m + w)) =>
	AddL 0 m v w where
	(++.) :: forall a .  RangeL 0 m a -> RangeL v w a -> RangeL v (m + w) a
	NilL ++. ys = loosenLMax ys
	x :.. xs ++. ys = x .:.. (xs ++. ys :: RangeL v (m + w - 1) a)

instance {-# OVERLAPPABLE #-}
	(1 <= n, AddL (n - 1) (m - 1) v w) => AddL n m v w where
	x :. xs ++. ys = x :. (xs ++. ys)

---------------------------------------------------------------------------
-- LOOSEN
---------------------------------------------------------------------------

-- LOOSEN LEFT

loosenL :: (LoosenLMin n m v, LoosenLMax v m w) => RangeL n m a -> RangeL v w a
loosenL = loosenLMax . loosenLMin

{-^

To loosen a range of an element number.

>>> :set -XDataKinds
>>> sampleLoosenL = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :.. NilL :: RangeL 4 6 Char
>>> loosenL sampleLoosenL :: RangeL 2 8 Char
'h' :. ('e' :. ('l' :.. ('l' :.. ('o' :.. NilL))))

-}

-- LOOSEN LEFT MIN

class LoosenLMin n m v where
	loosenLMin :: RangeL n m a -> RangeL v m a

	{-^

	To loosen a lower bound of an element number.

	>>> :set -XDataKinds -fno-warn-tabs
	>>> :{
		sampleLoosenLMin :: RangeL 4 6 Char
		sampleLoosenLMin = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :.. NilL
	:}

	>>> loosenLMin sampleLoosenLMin :: RangeL 2 6 Char
	'h' :. ('e' :. ('l' :.. ('l' :.. ('o' :.. NilL))))

	-}

instance LoosenLMin 0 m 0 where
	loosenLMin = \case NilL -> NilL; xs@(_ :.. _) -> xs

instance {-# OVERLAPPABLE #-}
	(1 <= n, LoosenLMin (n - 1) (m - 1) 0) => LoosenLMin n m 0 where
	loosenLMin (x :. xs) = x :.. loosenLMin xs
	
instance {-# OVERLAPPABLE #-}
	(1 <= n, 1 <= v, LoosenLMin (n - 1) (m - 1) (v - 1)) => LoosenLMin n m v where
	loosenLMin (x :. xs) = x :. loosenLMin xs

-- LOOSEN LEFT MAX

class LoosenLMax n m w where
	loosenLMax :: RangeL n m a -> RangeL n w a

	{-^

	To loosen an upper bound of an element number.

	>>> :set -XDataKinds -fno-warn-tabs
	>>> :{
		sampleLoosenLMax :: RangeL 4 6 Char
		sampleLoosenLMax = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :.. NilL
	:}

	>>> loosenLMax sampleLoosenLMax :: RangeL 4 8 Char
	'h' :. ('e' :. ('l' :. ('l' :. ('o' :.. NilL))))

	-}

instance LoosenLMax 0 0 w where loosenLMax NilL = NilL

instance {-# OVERLAPPABLE #-}
	(1 <= w, LoosenLMax 0 (m - 1) (w - 1)) => LoosenLMax 0 m w where
	loosenLMax = \case NilL -> NilL; (x :.. xs) -> x :.. loosenLMax xs

instance {-# OVERLAPPABLE #-}
	(1 <= n, 1 <= w, LoosenLMax (n - 1) (m - 1) (w - 1)) => LoosenLMax n m w where
	loosenLMax (x :. xs) = x :. loosenLMax xs

---------------------------------------------------------------------------
-- UNFOLDR
---------------------------------------------------------------------------

-- CLASS

class Unfoldr n v w where
	unfoldrMRangeWithBase :: Monad m =>
		RangeL n w a -> m Bool -> m a -> m (RangeL v w a)

	{-^
	
	It is like @unfoldrMRange@. But it has already prepared values.

	>>> :set -XDataKinds
	>>> :module + Data.IORef
	>>> r <- newIORef 1
	>>> check = (< 3) <$> readIORef r
	>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)
	>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer
	>>> unfoldrMRangeWithBase xs check count :: IO (RangeL 3 5 Integer)
	123 :. (456 :. (3 :. (6 :.. NilL)))
	
	-}

	unfoldrMRangeMaybeWithBase :: Monad m =>
		RangeL n w a -> m Bool -> m a -> m (Maybe (RangeL v w a))

	{-^
	
	It is like @unfoldrMRangeMaybe@.
	But it has already prepared values.

	>>> :set -XDataKinds -fno-warn-tabs
	>>> :module + Data.IORef
	>>> r <- newIORef 1
	>>> check = (< 3) <$> readIORef r
	>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)
	>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer
	>>> :{
		unfoldrMRangeMaybeWithBase xs check count
			:: IO (Maybe (RangeL 3 5 Integer))
	:}
	Just (123 :. (456 :. (3 :. (6 :.. NilL))))
	
	-}

-- INSTANCE

instance Unfoldr 0 0 0 where
	unfoldrMRangeWithBase NilL _ _ = pure NilL
	unfoldrMRangeMaybeWithBase NilL p _ = bool (Just NilL) Nothing <$> p

instance {-# OVERLAPPABLE #-} (1 <= w, Unfoldr 0 0 (w - 1)) => Unfoldr 0 0 w where
	unfoldrMRangeWithBase NilL p f =
		(p >>=) . bool (pure NilL) $ f >>= \x ->
			(x :..) <$> unfoldrMRangeWithBase NilL p f
	unfoldrMRangeWithBase (x :.. xs) p f =
		(x :..) <$> unfoldrMRangeWithBase xs p f

	unfoldrMRangeMaybeWithBase NilL p f =
		(p >>=) . bool (pure $ Just NilL) $ f >>= \x ->
			((x :..) <$>) <$> unfoldrMRangeMaybeWithBase NilL p f
	unfoldrMRangeMaybeWithBase (x :.. xs) p f =
		((x :..) <$>) <$> unfoldrMRangeMaybeWithBase xs p f

instance {-# OVERLAPPABLE #-}
	(1 <= v, 1 <= w, Unfoldr 0 (v - 1) (w - 1)) => Unfoldr 0 v w where
	unfoldrMRangeWithBase NilL p f =
		f >>= \x -> (x :.) <$> unfoldrMRangeWithBase NilL p f
	unfoldrMRangeWithBase (x :.. xs) p f =
		(x :.) <$> unfoldrMRangeWithBase xs p f

	unfoldrMRangeMaybeWithBase NilL p f =
		(p >>=) . bool (pure Nothing) $ f >>= \x ->
			((x :.) <$>) <$> unfoldrMRangeMaybeWithBase NilL p f
	unfoldrMRangeMaybeWithBase (x :.. xs) p f =
		((x :.) <$>) <$> unfoldrMRangeMaybeWithBase xs p f

instance {-# OVERLAPPABLE #-}
	(1 <= n, 1 <= v, Unfoldr (n - 1) (v - 1) (w - 1)) => Unfoldr n v w where
	unfoldrMRangeWithBase (x :. xs) p f =
		(x :.) <$> unfoldrMRangeWithBase xs p f

	unfoldrMRangeMaybeWithBase (x :. xs) p f =
		((x :.) <$>) <$> unfoldrMRangeMaybeWithBase xs p f

-- UNFOLDR RANGE

unfoldrRange :: Unfoldr 0 v w =>
	(s -> Bool) -> (s -> (a, s)) -> s -> RangeL v w a
unfoldrRange = unfoldrRangeWithBase NilL

{-^

To evaluate a function to construct a list.
The function recieve a state and return an element and a new state.
First argument is a predication which is evaluated
when an element number is greater than a minimum and not greater than a maximum.

>>> :set -XDataKinds
>>> next n = (n * 3, n + 1)
>>> unfoldrRange (< 2) next 1 :: RangeL 3 5 Int
3 :. (6 :. (9 :. NilL))

>>> unfoldrRange (< 5) next 1 :: RangeL 3 5 Int
3 :. (6 :. (9 :. (12 :.. NilL)))

>>> unfoldrRange (< 10) next 1 :: RangeL 3 5 Int
3 :. (6 :. (9 :. (12 :.. (15 :.. NilL))))

-}

unfoldrRangeWithBase :: Unfoldr n v w =>
	RangeL n w a -> (s -> Bool) -> (s -> (a, s)) -> s -> RangeL v w a
unfoldrRangeWithBase xs p f = fst . unfoldrRangeWithBaseWithS xs p f

{-^

It is like @unfoldrRange@. But it has already prepared values.

>>> :set -XDataKinds
>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer
>>> unfoldrRangeWithBase xs (< 3) (\n -> (n * 3, n + 1)) 1 :: RangeL 3 5 Integer
123 :. (456 :. (3 :. (6 :.. NilL)))

-}

unfoldrRangeWithBaseWithS :: Unfoldr n v w =>
	RangeL n w a -> (s -> Bool) -> (s -> (a, s)) -> s -> (RangeL v w a, s)
unfoldrRangeWithBaseWithS xs p f =
	runStateL $ unfoldrMRangeWithBase xs (StateL $ p &&& id) (StateL f)

{-^

It is like @unfoldrRangeWithBase@.
But it return not only a list but also a state value.

>>> :set -XDataKinds
>>> next n = (n * 3, n + 1)
>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer
>>> unfoldrRangeWithBaseWithS xs (< 3) next 1 :: (RangeL 3 5 Integer, Integer)
(123 :. (456 :. (3 :. (6 :.. NilL))),3)

-}

unfoldrMRange :: (Unfoldr 0 v w, Monad m) => m Bool -> m a -> m (RangeL v w a)
unfoldrMRange = unfoldrMRangeWithBase NilL

{-^

It is like @unfoldrRange@. But it use a monad instead of a function.

>>> :set -XDataKinds
>>> :module + Data.IORef
>>> r <- newIORef 1
>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)
>>> unfoldrMRange ((< 5) <$> readIORef r) count :: IO (RangeL 3 5 Integer)
3 :. (6 :. (9 :. (12 :.. NilL)))

-}

-- UNFOLDR RANGE MAYBE

unfoldrRangeMaybe :: Unfoldr 0 v w =>
	(s -> Maybe (a, s)) -> s -> Maybe (RangeL v w a)
unfoldrRangeMaybe = unfoldrRangeMaybeWithBase NilL

{-^

To eveluate a function to construct a list.
The function recieve a state and
return a nothing value or an element and a new state.
If number of created elements is less than a minimum number of list elements or
greater than a maximum number, then return Nothing.

>>> :set -XDataKinds
>>> next n0 n = if n < n0 then Just (n * 3, n + 1) else Nothing
>>> unfoldrRangeMaybe (next 2) 1 :: Maybe (RangeL 3 5 Int)
Nothing

>>> unfoldrRangeMaybe (next 5) 1 :: Maybe (RangeL 3 5 Int)
Just (3 :. (6 :. (9 :. (12 :.. NilL))))

>>> unfoldrRangeMaybe (next 10) 1 :: Maybe (RangeL 3 5 Int)
Nothing

-}

unfoldrRangeMaybeWithBase :: Unfoldr n v w =>
	RangeL n w a -> (s -> Maybe (a, s)) -> s -> Maybe (RangeL v w a)
unfoldrRangeMaybeWithBase xs f =
	fst . unfoldrRangeMaybeWithBaseGen xs (isJust &&& id)
		(maybe (error "never occur") (f `second`)) . f

{-^

It is like @unfoldrRangeMaybe@. But it has already prepared values.

>>> :set -XDataKinds
>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Int
>>> next n = if n < 3 then Just (n * 3, n + 1) else Nothing
>>> unfoldrRangeMaybeWithBase xs next 1 :: Maybe (RangeL 3 5 Int)
Just (123 :. (456 :. (3 :. (6 :.. NilL))))

-}

type St a s r = Maybe (a, s) -> (r, Maybe (a, s))

unfoldrRangeMaybeWithBaseGen :: Unfoldr n v w =>
	RangeL n w a -> St a s Bool -> St a s a -> St a s (Maybe (RangeL v w a))
unfoldrRangeMaybeWithBaseGen xs p f =
	runStateL $ unfoldrMRangeMaybeWithBase xs (StateL p) (StateL f)

unfoldrMRangeMaybe :: (Unfoldr 0 v w, Monad m) =>
	m Bool -> m a -> m (Maybe (RangeL v w a))
unfoldrMRangeMaybe = unfoldrMRangeMaybeWithBase NilL

{-^

It is like @unfoldrRangeMaybe@.
But it use a monad instead of a function.
The first argument monad return boolean value.
It create values while this boolean value is True.
If this boolean value is False before to create enough values or
True after to create full values, then @unfoldrMRangeMaybe@ return Nothing.

>>> :set -XDataKinds
>>> :module + Data.IORef
>>> r <- newIORef 1
>>> check n0 = (< n0) <$> readIORef r
>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)
>>> unfoldrMRangeMaybe (check 2) count :: IO (Maybe (RangeL 3 5 Integer))
Nothing

>>> writeIORef r 1
>>> unfoldrMRangeMaybe (check 5) count :: IO (Maybe (RangeL 3 5 Integer))
Just (3 :. (6 :. (9 :. (12 :.. NilL))))

>>> writeIORef r 1
>>> unfoldrMRangeMaybe (check 10) count :: IO (Maybe (RangeL 3 5 Integer))
Nothing

-}

---------------------------------------------------------------------------
-- ZIP
---------------------------------------------------------------------------

-- CLASS

class ZipL n m v w where
	zipWithML :: Monad q =>
		(a -> b -> q c) -> RangeL n m a -> RangeL v w b ->
		q (RangeL n m c, RangeL (v - m) (w - n) b)

	{-^

	It is like @zipWithL@.
	But it use a function which return a monad instead of a simple value.

	>>> :set -XDataKinds -fno-warn-tabs
	>>> ns = 1 :. 2 :. 3 :.. NilL :: RangeL 2 4 Int
	>>> :{
		cs :: RangeL 5 7 Char
		cs = 'a' :. 'b' :. 'c' :. 'd' :. 'e' :. 'f' :.. NilL
	:}

	>>> zipWithML (\n -> putStrLn . replicate n) ns cs
	a
	bb
	ccc
	(() :. (() :. (() :.. NilL)),'d' :. ('e' :.. ('f' :.. NilL)))

	-}

instance ZipL 0 0 v w where zipWithML _ NilL = pure . (NilL ,)

instance {-# OVERLAPPABLE #-} (
	1 <= v, m <= v, LoosenLMin v w (v - m), LoosenLMax (v - m) (w - 1) w,
	ZipL 0 (m - 1) (v - 1) (w - 1) ) => ZipL 0 m v w where
	zipWithML _ NilL ys = pure (NilL, loosenLMin ys)
	zipWithML (%) (x :.. xs) (y :. ys) =
		x % y >>= \z -> ((z :..) *** loosenLMax) <$> zipWithML (%) xs ys

instance {-# OVERLAPPABLE #-} (
	1 <= n, 1 <= v, n <= w, m <= v,
	ZipL (n - 1) (m - 1) (v - 1) (w - 1) ) => ZipL n m v w where
	zipWithML (%) (x :. xs) (y :. ys) =
		x % y >>= \z -> ((z :.) `first`) <$> zipWithML (%) xs ys

-- FUNCTION

zipL :: ZipL n m v w => RangeL n m a -> RangeL v w b ->
	(RangeL n m (a, b), RangeL (v - m) (w - n) b)
zipL = zipWithL (,)

{-^

To recieve two lists and return a tuple list and rest of the second list.
The first list must be shorter or equal than the second list.

>>> :set -XDataKinds
>>> sampleZipL1 = 1 :. 2 :. 3 :.. NilL :: RangeL 2 4 Integer
>>> sampleZipL2 = 7 :. 6 :. 5 :. 4 :. 3 :. 2 :.. NilL :: RangeL 5 7 Integer
>>> zipL sampleZipL1 sampleZipL2
((1,7) :. ((2,6) :. ((3,5) :.. NilL)),4 :. (3 :.. (2 :.. NilL)))
>>> :type zipL sampleZipL1 sampleZipL2
zipL sampleZipL1 sampleZipL2
  :: (RangeL 2 4 (Integer, Integer), RangeL 1 5 Integer)

-}

zipWithL :: ZipL n m v w => (a -> b -> c) -> RangeL n m a -> RangeL v w b ->
	(RangeL n m c, RangeL (v - m) (w - n) b)
zipWithL op = (runIdentity .) . zipWithML ((Identity .) . op)

{-^

It is like @zipL@.
But it evaluate a function to make values instead of put together in tuples.

>>> :set -XDataKinds
>>> sampleZipWithL1 = 1 :. 2 :. 3 :.. NilL :: RangeL 2 4 Integer
>>> sampleZipWithL2 = 7 :. 6 :. 5 :. 4 :. 3 :. 2 :.. NilL :: RangeL 5 7 Integer
>>> zipWithL (+) sampleZipWithL1 sampleZipWithL2
(8 :. (8 :. (8 :.. NilL)),4 :. (3 :.. (2 :.. NilL)))
>>> :type zipWithL (+) sampleZipWithL1 sampleZipWithL2
zipWithL (+) sampleZipWithL1 sampleZipWithL2
  :: (RangeL 2 4 Integer, RangeL 1 5 Integer)

-}