{- |
Copyright: (c) 2020 Kowainik
SPDX-License-Identifier: MPL-2.0
Maintainer: Kowainik <xrom.xkov@gmail.com>

Extra functions to work with lists.
-}

module Stan.Core.List
    ( checkWith
    , nonRepeatingPairs
    ) where

{- | Checks that two lists have the same length and that a given
binary predicate returns 'True' on each corresponding pair of
elements.

>>> checkWith (==) [] []
True
>>> checkWith (==) [1, 2] [1, 2]
True
>>> checkWith (==) [1, 2] [2, 1]
False
>>> checkWith (==) [1, 2] [1]
False
-}
checkWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
checkWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
checkWith _ [] []         = Bool
True
checkWith _ [] _          = Bool
False
checkWith _ _ []          = Bool
False
checkWith f :: a -> b -> Bool
f (a :: a
a:as :: [a]
as) (b :: b
b:bs :: [b]
bs) = a -> b -> Bool
f a
a b
b Bool -> Bool -> Bool
&& (a -> b -> Bool) -> [a] -> [b] -> Bool
forall a b. (a -> b -> Bool) -> [a] -> [b] -> Bool
checkWith a -> b -> Bool
f [a]
as [b]
bs

{- | Returns list all element pairs without the following properties:

* No element with itself: @(x, x)@
* Only one of @(x, y)@ and @(y, x)@ will be in the result

In other words, it's like taking the cross product of the list with
itself and then keeping only the half of that without the diagonal.

>>> foo [1..3]
[(1, 2), (1, 3), (2, 3)]
-}
nonRepeatingPairs :: [a] -> [(a, a)]
nonRepeatingPairs :: [a] -> [(a, a)]
nonRepeatingPairs []     = []
nonRepeatingPairs (x :: a
x:xs :: [a]
xs) = (a -> (a, a)) -> [a] -> [(a, a)]
forall a b. (a -> b) -> [a] -> [b]
map (a
x,) [a]
xs [(a, a)] -> [(a, a)] -> [(a, a)]
forall a. [a] -> [a] -> [a]
++ [a] -> [(a, a)]
forall a. [a] -> [(a, a)]
nonRepeatingPairs [a]
xs