{-| Module  : FiniteCategories
Description : Simple functions to compute cartesian products of finite lists.
Copyright   : Guillaume Sabbagh 2021
License     : GPL-3
Maintainer  : guillaumesabbagh@protonmail.com
Stability   : experimental
Portability : portable

Simple functions to compute cartesian products of finite lists.
-}

module Utils.CartesianProduct
(
    cartesianProduct,
    cartesianPower,
    (|*|),
    (|^|)
)
where
    import Data.List (replicate)

    -- | Returns the cartesian product of the finite lists.

    --

    -- cartesianProduct [A,B,C,...] = A x B x C x ...

    cartesianProduct :: [[a]] -> [[a]]
    cartesianProduct :: forall a. [[a]] -> [[a]]
cartesianProduct [] = [[]]
    cartesianProduct ([a]
x:[[a]]
xs) = [[[a]]] -> [[a]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ((\[a]
l -> [a
ea -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
l | a
e <- [a]
x]) ([a] -> [[a]]) -> [[a]] -> [[[a]]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([[a]] -> [[a]]
forall a. [[a]] -> [[a]]
cartesianProduct [[a]]
xs))
    
    -- | Returns the cartesian product of two lists

    (|*|) :: [a] -> [a] -> [[a]]
    [a]
x |*| :: forall a. [a] -> [a] -> [[a]]
|*| [a]
y = [[a]] -> [[a]]
forall a. [[a]] -> [[a]]
cartesianProduct [[a]
x,[a]
y]

    -- | Returns the cartesian product of a list by itself /k/ times.

    cartesianPower :: [a] -> Int -> [[a]]
    cartesianPower :: forall a. [a] -> Int -> [[a]]
cartesianPower [a]
l Int
k = [[a]] -> [[a]]
forall a. [[a]] -> [[a]]
cartesianProduct ([[a]] -> [[a]]) -> [[a]] -> [[a]]
forall a b. (a -> b) -> a -> b
$ Int -> [a] -> [[a]]
forall a. Int -> a -> [a]
replicate Int
k [a]
l
    
    -- | Infix alias for `cartesianPower`

    |^| :: [a] -> Int -> [[a]]
(|^|) = [a] -> Int -> [[a]]
forall a. [a] -> Int -> [[a]]
cartesianPower