{-# LANGUAGE CPP #-}
-- |
-- Module      : Test.LeanCheck.Stats
-- Copyright   : (c) 2017-2024 Rudy Matela
-- License     : 3-Clause BSD  (see the file LICENSE)
-- Maintainer  : Rudy Matela <rudy@matela.com.br>
--
-- This module is part of LeanCheck,
-- a simple enumerative property-based testing library.
--
-- This module exports functions to compute statistics of Listable instances.
module Test.LeanCheck.Stats
  ( classStats
  , classStatsT
  , conditionStats
  , conditionStatsT

  , classify
  , classifyBy
  , classifyOn
  , counts
  , countsBy
  , countsOn
  )
where

import Test.LeanCheck.Core
import Data.Function (on)
#ifndef __HUGS__
import Data.List (intercalate, transpose)
#else
import Data.List (transpose)

intercalate :: [a] -> [[a]] -> [a]
intercalate xs xss  =  concat (intersperse xs xss)
  where
  intersperse :: a -> [a] -> [a]
  intersperse _ []        =  []
  intersperse sep (x:xs)  =  x : prependToAll sep xs
    where
    prependToAll :: a -> [a] -> [a]
    prependToAll _   []      =  []
    prependToAll sep (x:xs)  =  sep : x : prependToAll sep xs
#endif

-- | Prints statistics about a given 'Listable' generator
--   up to a number of test values.
--
-- For example,
-- to know the distribution of the length of generated lists,
-- just run:
--
-- > > classStats 100 (length :: [Int] -> Int)
-- > 0:  1/100  1%
-- > 1:  6/100  6%
-- > 2: 16/100 16%
-- > 3: 25/100 25%
-- > 4: 26/100 26%
-- > 5: 18/100 18%
-- > 6:  7/100  7%
-- > 7:  1/100  1%
--
-- This provides similar functionality to QuickCheck's
-- label, collect, classify and tabulate
-- while keeping statistics separate from your properties.
classStats :: (Listable a, Show b) => Int -> (a -> b) -> IO ()
classStats :: forall a b. (Listable a, Show b) => Int -> (a -> b) -> IO ()
classStats Int
n a -> b
f  =  [Char] -> IO ()
putStrLn
                ([Char] -> IO ())
-> ([([Char], Int)] -> [Char]) -> [([Char], Int)] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> [[[Char]]] -> [Char]
table [Char]
" "
                ([[[Char]]] -> [Char])
-> ([([Char], Int)] -> [[[Char]]]) -> [([Char], Int)] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (([Char], Int) -> [[Char]]) -> [([Char], Int)] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], Int) -> [[Char]]
showCount
                ([([Char], Int)] -> IO ()) -> [([Char], Int)] -> IO ()
forall a b. (a -> b) -> a -> b
$  (a -> [Char]) -> [a] -> [([Char], Int)]
forall b a. Eq b => (a -> b) -> [a] -> [(b, Int)]
countsOn ([Char] -> [Char]
unquote ([Char] -> [Char]) -> (a -> [Char]) -> a -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> [Char]
forall a. Show a => a -> [Char]
show (b -> [Char]) -> (a -> b) -> a -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f) [a]
xs
  where
  xs :: [a]
xs  =  Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
n [a]
forall a. Listable a => [a]
list
  len :: Int
len  =  [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs
  showCount :: ([Char], Int) -> [[Char]]
showCount ([Char]
s,Int
n)  =  [ [Char]
s [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
":"
                      , Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"/" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
len
                      , Int -> [Char]
forall a. Show a => a -> [Char]
show (Int
100 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
len) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"%"
                      ]

-- | Same as 'classStats', but separated by 'tiers'.
--
-- The first argument is the number of tiers to evaluate.
--
-- > > classStatsT 6 (length :: [Int] -> Int)
-- >       tot   0  1  2  3  4   5
-- > 
-- > tot:   32   1  1  2  4  8  16
-- >   0:    1   1  0  0  0  0   0
-- >   1:    5   0  1  1  1  1   1
-- >   2:   10   0  0  1  2  3   4
-- >   3:   10   0  0  0  1  3   6
-- >   4:    5   0  0  0  0  1   4
-- >   5:    1   0  0  0  0  0   1
--
-- Lines are values, columns are tiers:
--
-- > > classStatsT 6 and
-- >         tot   0  1  2  3   4   5
-- > 
-- >   tot:   63   1  2  4  8  16  32
-- >  True:    6   1  1  1  1   1   1
-- > False:   57   0  1  3  7  15  31
classStatsT :: (Listable a, Show b) => Int -> (a -> b) -> IO ()
classStatsT :: forall a b. (Listable a, Show b) => Int -> (a -> b) -> IO ()
classStatsT Int
n a -> b
f  =  [Char] -> IO ()
putStrLn
                 ([Char] -> IO ()) -> ([[a]] -> [Char]) -> [[a]] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> [[[Char]]] -> [Char]
table [Char]
"  "
                 ([[[Char]]] -> [Char]) -> ([[a]] -> [[[Char]]]) -> [[a]] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ([[Char]]
heading[[Char]] -> [[[Char]]] -> [[[Char]]]
forall a. a -> [a] -> [a]
:)
                 ([[[Char]]] -> [[[Char]]])
-> ([[a]] -> [[[Char]]]) -> [[a]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ([[Char]
" "][[Char]] -> [[[Char]]] -> [[[Char]]]
forall a. a -> [a] -> [a]
:)
                 ([[[Char]]] -> [[[Char]]])
-> ([[a]] -> [[[Char]]]) -> [[a]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (([Char], Int, [Int]) -> [[Char]])
-> [([Char], Int, [Int])] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], Int, [Int]) -> [[Char]]
forall {a} {a}. (Show a, Show a) => ([Char], a, [a]) -> [[Char]]
showCounts
                 ([([Char], Int, [Int])] -> [[[Char]]])
-> ([[a]] -> [([Char], Int, [Int])]) -> [[a]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [([Char], Int, [Int])] -> [([Char], Int, [Int])]
prependTotal
                 ([([Char], Int, [Int])] -> [([Char], Int, [Int])])
-> ([[a]] -> [([Char], Int, [Int])])
-> [[a]]
-> [([Char], Int, [Int])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (a -> [Char]) -> [[a]] -> [([Char], Int, [Int])]
forall b a. Eq b => (a -> b) -> [[a]] -> [(b, Int, [Int])]
countsTOn ([Char] -> [Char]
unquote ([Char] -> [Char]) -> (a -> [Char]) -> a -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> [Char]
forall a. Show a => a -> [Char]
show (b -> [Char]) -> (a -> b) -> a -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f)
                 ([[a]] -> IO ()) -> [[a]] -> IO ()
forall a b. (a -> b) -> a -> b
$  Int -> [[a]] -> [[a]]
forall a. Int -> [a] -> [a]
take Int
n [[a]]
forall a. Listable a => [[a]]
tiers
  where
  heading :: [[Char]]
heading  =  [Char]
"" [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: [Char]
"tot " [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: (Int -> [Char]) -> [Int] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map Int -> [Char]
forall a. Show a => a -> [Char]
show [Int
0..(Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)]
  showCounts :: ([Char], a, [a]) -> [[Char]]
showCounts ([Char]
s,a
n,[a]
ns)  =  ([Char]
s [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
":") [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: (a -> [Char]
forall a. Show a => a -> [Char]
show a
n [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" ") [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: (a -> [Char]) -> [a] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map a -> [Char]
forall a. Show a => a -> [Char]
show [a]
ns
  (a
_,b
n,[c]
ns) -+- :: (a, b, [c]) -> (a, b, [c]) -> ([Char], b, [c])
-+- (a
_,b
n',[c]
ns')  =  ([Char]
"tot", b
n b -> b -> b
forall a. Num a => a -> a -> a
+ b
n', (c -> c -> c) -> [c] -> [c] -> [c]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith c -> c -> c
forall a. Num a => a -> a -> a
(+) [c]
ns [c]
ns')
  totalizeCounts :: [(a, Int, [Int])] -> ([Char], Int, [Int])
totalizeCounts  =  ((a, Int, [Int]) -> ([Char], Int, [Int]) -> ([Char], Int, [Int]))
-> ([Char], Int, [Int])
-> [(a, Int, [Int])]
-> ([Char], Int, [Int])
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (a, Int, [Int]) -> ([Char], Int, [Int]) -> ([Char], Int, [Int])
forall {b} {c} {a} {a}.
(Num b, Num c) =>
(a, b, [c]) -> (a, b, [c]) -> ([Char], b, [c])
(-+-) ([Char]
forall a. HasCallStack => a
undefined, Int
0, Int -> [Int]
forall a. a -> [a]
repeat Int
0)
  prependTotal :: [([Char], Int, [Int])] -> [([Char], Int, [Int])]
prependTotal [([Char], Int, [Int])]
cs  =  [([Char], Int, [Int])] -> ([Char], Int, [Int])
forall {a}. [(a, Int, [Int])] -> ([Char], Int, [Int])
totalizeCounts [([Char], Int, [Int])]
cs ([Char], Int, [Int])
-> [([Char], Int, [Int])] -> [([Char], Int, [Int])]
forall a. a -> [a] -> [a]
: [([Char], Int, [Int])]
cs

-- | How many values match each of a list of conditions?
-- 
-- How many odd and even numbers are in the 'Listable' enumeration?
--
-- > > conditionStats 1000 [("odd", odd :: Int -> Bool), ("even", even)]
-- >  odd: 500/1000 50%
-- > even: 500/1000 50%
--
-- How many of the generated lists are ordered?
--
-- > > conditionStats 1000 [("ordered", ordered :: [Int] -> Bool)]
-- > ordered: 131/1000 13%
conditionStats :: Listable a => Int -> [(String,a->Bool)] -> IO ()
conditionStats :: forall a. Listable a => Int -> [([Char], a -> Bool)] -> IO ()
conditionStats Int
n  =  [Char] -> IO ()
putStrLn ([Char] -> IO ())
-> ([([Char], a -> Bool)] -> [Char])
-> [([Char], a -> Bool)]
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[[Char]]] -> [Char]
table [Char]
" " ([[[Char]]] -> [Char])
-> ([([Char], a -> Bool)] -> [[[Char]]])
-> [([Char], a -> Bool)]
-> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([Char], a -> Bool) -> [[Char]])
-> [([Char], a -> Bool)] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], a -> Bool) -> [[Char]]
show1
  where
  xs :: [a]
xs  =  Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
n [a]
forall a. Listable a => [a]
list
  len :: Int
len  =  [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs
  show1 :: ([Char], a -> Bool) -> [[Char]]
show1 ([Char]
s,a -> Bool
f)  =  [ [Char]
s [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
":"
                  , Int -> [Char]
forall a. Show a => a -> [Char]
show Int
c [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"/" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
len
                  , Int -> [Char]
forall a. Show a => a -> [Char]
show (Int
100 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
c Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
len) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"%"
                  ]  where  c :: Int
c = (a -> Bool) -> [a] -> Int
forall {a}. (a -> Bool) -> [a] -> Int
count a -> Bool
f [a]
xs
  count :: (a -> Bool) -> [a] -> Int
count a -> Bool
f  =  [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([a] -> Int) -> ([a] -> [a]) -> [a] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter a -> Bool
f

-- | Same as 'conditionStats' but by tier.
--
-- The first argument is the number of tiers to evaluate.
--
-- How many odd and even numbers are in each tier?
--
-- > > conditionStatsT 10 [("odd", odd :: Int -> Bool), ("even", even)]
-- > total: 1 1 1 1 1 1 1 1 1 1
-- >   odd: 0 1 1 0 0 1 1 0 0 1
-- >  even: 1 0 0 1 1 0 0 1 1 0
--
-- How many ordered lists are in each tier?
--
-- > > conditionStatsT 10 [("ordered", ordered :: [Int] -> Bool)]
-- >   total: 1 1 2 4 8 16 32 64 128 256
-- > ordered: 1 1 2 3 5  7 11 15  22  30
conditionStatsT :: Listable a => Int -> [(String,a->Bool)] -> IO ()
conditionStatsT :: forall a. Listable a => Int -> [([Char], a -> Bool)] -> IO ()
conditionStatsT Int
n  =  [Char] -> IO ()
putStrLn
                   ([Char] -> IO ())
-> ([([Char], a -> Bool)] -> [Char])
-> [([Char], a -> Bool)]
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> [[[Char]]] -> [Char]
table [Char]
" "
                   ([[[Char]]] -> [Char])
-> ([([Char], a -> Bool)] -> [[[Char]]])
-> [([Char], a -> Bool)]
-> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (([Char], a -> Bool) -> [[Char]])
-> [([Char], a -> Bool)] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], a -> Bool) -> [[Char]]
show1
                   ([([Char], a -> Bool)] -> [[[Char]]])
-> ([([Char], a -> Bool)] -> [([Char], a -> Bool)])
-> [([Char], a -> Bool)]
-> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (([Char]
"total", Bool -> a -> Bool
forall a b. a -> b -> a
const Bool
True)([Char], a -> Bool)
-> [([Char], a -> Bool)] -> [([Char], a -> Bool)]
forall a. a -> [a] -> [a]
:)
  where
  xss :: [[a]]
xss  =  Int -> [[a]] -> [[a]]
forall a. Int -> [a] -> [a]
take Int
n [[a]]
forall a. Listable a => [[a]]
tiers
  show1 :: ([Char], a -> Bool) -> [[Char]]
show1 ([Char]
s,a -> Bool
f)  =  ([Char]
s [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
":") [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: ([a] -> [Char]) -> [[a]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [Char]
forall a. Show a => a -> [Char]
show (Int -> [Char]) -> ([a] -> Int) -> [a] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> Int
forall {a}. (a -> Bool) -> [a] -> Int
count a -> Bool
f) [[a]]
xss
  count :: (a -> Bool) -> [a] -> Int
count a -> Bool
f  =  [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([a] -> Int) -> ([a] -> [a]) -> [a] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter a -> Bool
f

-- | Classify values using their 'Eq' instance.
--
-- > > classify [1,2,3,1,2,1]
-- > [[1,1,1],[2,2],[3]]
--
-- (cf. 'classifyBy', 'classifyOn')
classify :: Eq a => [a] -> [[a]]
classify :: forall a. Eq a => [a] -> [[a]]
classify  =  (a -> a -> Bool) -> [a] -> [[a]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
classifyBy a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==)

-- | Classify values by a given comparison function.
--
-- > > classifyBy (\(x,_) (y,_) -> x == y) [(1,1),(1,2),(2,1),(2,2)]
-- > [[(1,1),(1,2)],[(2,1),(2,2)]]
--
-- (cf. 'classify', 'classifyOn')
classifyBy :: (a -> a -> Bool) -> [a] -> [[a]]
classifyBy :: forall a. (a -> a -> Bool) -> [a] -> [[a]]
classifyBy a -> a -> Bool
(==) []      =  []
classifyBy a -> a -> Bool
(==) (a
x:[a]
xs)  =  (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:(a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> a -> Bool
== a
x) [a]
xs)
                        [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
:  (a -> a -> Bool) -> [a] -> [[a]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
classifyBy a -> a -> Bool
(==) ((a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> a -> Bool
/= a
x) [a]
xs)
  where
  a
x /= :: a -> a -> Bool
/= a
y  =  Bool -> Bool
not (a
x a -> a -> Bool
== a
y)

-- | Classify values based on the result of a given function.
--
-- > > classifyOn head ["sheep", "chip", "ship", "cheap"]
-- > [["sheep","ship"],["chip","cheap"]]
--
-- > > classifyOn odd [1,2,3,4,5,6]
-- > [[1,3,5],[2,4,6]]
--
-- (cf. 'classify', 'classifyBy')
classifyOn :: Eq b => (a -> b) -> [a] -> [[a]]
classifyOn :: forall b a. Eq b => (a -> b) -> [a] -> [[a]]
classifyOn a -> b
f [a]
xs  =  ([(a, b)] -> [a]) -> [[(a, b)]] -> [[a]]
forall a b. (a -> b) -> [a] -> [b]
map (((a, b) -> a) -> [(a, b)] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (a, b) -> a
forall a b. (a, b) -> a
fst)
                 ([[(a, b)]] -> [[a]])
-> ([(a, b)] -> [[(a, b)]]) -> [(a, b)] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ((a, b) -> (a, b) -> Bool) -> [(a, b)] -> [[(a, b)]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
classifyBy (b -> b -> Bool
forall a. Eq a => a -> a -> Bool
(==) (b -> b -> Bool) -> ((a, b) -> b) -> (a, b) -> (a, b) -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (a, b) -> b
forall a b. (a, b) -> b
snd)
                 ([(a, b)] -> [[a]]) -> [(a, b)] -> [[a]]
forall a b. (a -> b) -> a -> b
$  (a -> (a, b)) -> [a] -> [(a, b)]
forall a b. (a -> b) -> [a] -> [b]
map (\a
x -> (a
x,a -> b
f a
x)) [a]
xs

-- | Returns the counts of each value in a list.
--
-- > > counts "Mississippi"
-- > [('M',1),('i',4),('s',4),('p',2)]
--
-- Values are returned in the order they appear.
counts :: Eq a => [a] -> [(a,Int)]
counts :: forall a. Eq a => [a] -> [(a, Int)]
counts  =  ([a] -> (a, Int)) -> [[a]] -> [(a, Int)]
forall a b. (a -> b) -> [a] -> [b]
map [a] -> (a, Int)
forall a. [a] -> (a, Int)
headLength ([[a]] -> [(a, Int)]) -> ([a] -> [[a]]) -> [a] -> [(a, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [[a]]
forall a. Eq a => [a] -> [[a]]
classify

-- | Returns the counts of each value in a list
--   using a given comparison function.
countsBy :: (a -> a -> Bool) -> [a] -> [(a,Int)]
countsBy :: forall a. (a -> a -> Bool) -> [a] -> [(a, Int)]
countsBy a -> a -> Bool
(==)  =  ([a] -> (a, Int)) -> [[a]] -> [(a, Int)]
forall a b. (a -> b) -> [a] -> [b]
map [a] -> (a, Int)
forall a. [a] -> (a, Int)
headLength ([[a]] -> [(a, Int)]) -> ([a] -> [[a]]) -> [a] -> [(a, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> Bool) -> [a] -> [[a]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
classifyBy a -> a -> Bool
(==)

-- | Returns the counts of each value in a list
--   based on a projection.
--
-- > > countsOn length ["sheep", "chip", "ship", "cheap", "Mississippi"]
-- > [(5,2),(4,2),(11,1)]
countsOn :: Eq b => (a -> b) -> [a] -> [(b,Int)]
countsOn :: forall b a. Eq b => (a -> b) -> [a] -> [(b, Int)]
countsOn a -> b
f  =  ([a] -> (b, Int)) -> [[a]] -> [(b, Int)]
forall a b. (a -> b) -> [a] -> [b]
map ((a -> b) -> (a, Int) -> (b, Int)
forall {t} {a} {b}. (t -> a) -> (t, b) -> (a, b)
first a -> b
f ((a, Int) -> (b, Int)) -> ([a] -> (a, Int)) -> [a] -> (b, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> (a, Int)
forall a. [a] -> (a, Int)
headLength) ([[a]] -> [(b, Int)]) -> ([a] -> [[a]]) -> [a] -> [(b, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> [a] -> [[a]]
forall b a. Eq b => (a -> b) -> [a] -> [[a]]
classifyOn a -> b
f
  where
  first :: (t -> a) -> (t, b) -> (a, b)
first t -> a
f (t
x,b
y)  =  (t -> a
f t
x, b
y)

countsT :: Eq a => [[a]] -> [(a,Int,[Int])]
countsT :: forall a. Eq a => [[a]] -> [(a, Int, [Int])]
countsT [[a]]
xss  =  [(a
x,Int
n,([a] -> Int) -> [[a]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (a -> [a] -> Int
forall {a}. Eq a => a -> [a] -> Int
count a
x) [[a]]
xss) | (a
x,Int
n) <- [a] -> [(a, Int)]
forall a. Eq a => [a] -> [(a, Int)]
counts ([[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[a]]
xss)]
  where
  count :: a -> [a] -> Int
count a
x  =  [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([a] -> Int) -> ([a] -> [a]) -> [a] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x)

countsTOn :: Eq b => (a -> b) -> [[a]] -> [(b,Int,[Int])]
countsTOn :: forall b a. Eq b => (a -> b) -> [[a]] -> [(b, Int, [Int])]
countsTOn a -> b
f  =  [[b]] -> [(b, Int, [Int])]
forall a. Eq a => [[a]] -> [(a, Int, [Int])]
countsT ([[b]] -> [(b, Int, [Int])])
-> ([[a]] -> [[b]]) -> [[a]] -> [(b, Int, [Int])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> [[a]] -> [[b]]
forall a b. (a -> b) -> [[a]] -> [[b]]
mapT a -> b
f

headLength :: [a] -> (a,Int)
headLength :: forall a. [a] -> (a, Int)
headLength []  =  ([Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"Test.LeanCheck.Stats.headLength: empty list", Int
0)
headLength xs :: [a]
xs@(a
x:[a]
_)  =  (a
x, [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs)

unquote :: String -> String
unquote :: [Char] -> [Char]
unquote (Char
'"':[Char]
s) | [Char] -> Char
forall a. HasCallStack => [a] -> a
last [Char]
s Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'"'  =  [Char] -> [Char]
forall a. HasCallStack => [a] -> [a]
init [Char]
s
unquote [Char]
s  =  [Char]
s

table :: String -> [[String]] -> String
table :: [Char] -> [[[Char]]] -> [Char]
table [Char]
s []   =  [Char]
""
table [Char]
s [[[Char]]]
sss  =  [[Char]] -> [Char]
unlines
             ([[Char]] -> [Char])
-> ([[[Char]]] -> [[Char]]) -> [[[Char]]] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ([[Char]] -> [Char]) -> [[[Char]]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (Char -> [Char] -> [Char]
forall a. Eq a => a -> [a] -> [a]
removeTrailing Char
' ' ([Char] -> [Char]) -> ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
s)
             ([[[Char]]] -> [[Char]])
-> ([[[Char]]] -> [[[Char]]]) -> [[[Char]]] -> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [[[Char]]] -> [[[Char]]]
forall a. [[a]] -> [[a]]
transpose
             ([[[Char]]] -> [[[Char]]])
-> ([[[Char]]] -> [[[Char]]]) -> [[[Char]]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ([[Char]] -> [[Char]]) -> [[[Char]]] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map (Char -> [[Char]] -> [[Char]]
forall a. a -> [[a]] -> [[a]]
normalize Char
' ')
             ([[[Char]]] -> [[[Char]]])
-> ([[[Char]]] -> [[[Char]]]) -> [[[Char]]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ([[[Char]]] -> [[[Char]]] -> [[[Char]]])
-> [[[[Char]]]] -> [[[Char]]]
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 (([[Char]] -> [[Char]] -> [[Char]])
-> [[[Char]]] -> [[[Char]]] -> [[[Char]]]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
(++))
             ([[[[Char]]]] -> [[[Char]]])
-> ([[[Char]]] -> [[[[Char]]]]) -> [[[Char]]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ([[Char]] -> [[[Char]]]) -> [[[Char]]] -> [[[[Char]]]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char] -> [[[Char]]] -> [[[Char]]]
forall a. a -> [[a]] -> [[a]]
normalize [Char]
"" ([[[Char]]] -> [[[Char]]])
-> ([[Char]] -> [[[Char]]]) -> [[Char]] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> [[Char]]) -> [[Char]] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map [Char] -> [[Char]]
lines)
             ([[[Char]]] -> [[[[Char]]]])
-> ([[[Char]]] -> [[[Char]]]) -> [[[Char]]] -> [[[[Char]]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> [[[Char]]] -> [[[Char]]]
forall a. a -> [[a]] -> [[a]]
normalize [Char]
""
             ([[[Char]]] -> [Char]) -> [[[Char]]] -> [Char]
forall a b. (a -> b) -> a -> b
$  [[[Char]]]
sss

-- | Fits a list to a certain width by appending a certain value
--
-- > fit ' ' 6 "str" == "str   "
--
-- > fit 0 6 [1,2,3] == [1,2,3,0,0,0]
fit :: a -> Int -> [a] -> [a]
fit :: forall a. a -> Int -> [a] -> [a]
fit a
x Int
n [a]
xs  =  Int -> a -> [a]
forall a. Int -> a -> [a]
replicate (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs) a
x [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
xs

-- | normalize makes all list the same length by adding a value
--
-- > normalize ["asdf","qw","er"] == normalize ["asdf","qw  ","er  "]
normalize :: a -> [[a]] -> [[a]]
normalize :: forall a. a -> [[a]] -> [[a]]
normalize a
x [[a]]
xs  =  ([a] -> [a]) -> [[a]] -> [[a]]
forall a b. (a -> b) -> [a] -> [b]
map (a
x a -> Int -> [a] -> [a]
forall a. a -> Int -> [a] -> [a]
`fit` [[a]] -> Int
forall a. [[a]] -> Int
maxLength [[a]]
xs) [[a]]
xs

-- | Given a list of lists returns the maximum length
maxLength :: [[a]] -> Int
maxLength :: forall a. [[a]] -> Int
maxLength  =  [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Int] -> Int) -> ([[a]] -> [Int]) -> [[a]] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int
0Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:) ([Int] -> [Int]) -> ([[a]] -> [Int]) -> [[a]] -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([a] -> Int) -> [[a]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length

removeTrailing :: Eq a => a -> [a] -> [a]
removeTrailing :: forall a. Eq a => a -> [a] -> [a]
removeTrailing a
x  =  [a] -> [a]
forall a. [a] -> [a]
reverse
                  ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
==a
x)
                  ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [a] -> [a]
forall a. [a] -> [a]
reverse