# 03-Generating-Random-Data.purs

-- | The focus of this file is on how to use combinators.
-- | to produce random data.
module Test.RandomDataGeneration.Combinators where

import Prelude
import Data.Maybe (fromJust)
import Effect (Effect)
import Effect.Console (log)
import Data.Array.NonEmpty as NEA

-- new imports
-- these are all explained below
import Test.QuickCheck.Gen (
uniform
, choose, chooseInt, elements, shuffle
, oneOf, frequency, suchThat
, arrayOf, arrayOf1, listOf, vectorOf

-- all imports below this line are needed to compile
, Gen, randomSample
)
import Data.Int (even)
import Data.Traversable (for)
import Data.Tuple (Tuple(..))
import Partial.Unsafe (unsafePartial)

-- Prints the results of the combinators in Test.QuickCheck.Gen
main :: Effect Unit
main = do                                                                 {-
printData "explanation" $combinator arg1 arg2 -- if args are required -} log "*** Basic combinators ***" -- see "Standard Uniform Distribution" section in -- https://www.wikiwand.com/en/Uniform_distribution_(continuous) printData "uniform - standard uniform distribution"$
uniform

printData "chooseInt - choose a random Int between" $chooseInt 1 10 printData "choose - choose a random Number between"$
choose    1.0 10.0

-- oneToThree = NonEmptyArray [1, 2, 3]
let oneToThree = unsafePartial fromJust $NEA.fromArray [1, 2, 3] printData ("elements - Choose an random element from the array where \ \each element has the same probability of being chosen")$
elements oneToThree

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
printData ("shuffle - randomize the order of an array's elements \
\(e.g. " <> show array <> ")") $shuffle array log "*** Composable combinators ***" printData ("oneOf - Randomly choose a generator (where each generator has \ \the same probability of being chosen) and use it to generate \ \a random instance of the data type")$
oneOf $unsafePartial fromJust$ NEA.fromArray
[ chooseInt   0   9
, chooseInt  10  99
, chooseInt 100 999
]

let array_1 = NEA.singleton 1 -- (NonEmptyArray Int)
array_2 = NEA.singleton 2
array_4 = NEA.singleton 4
lessOften = 1.0
sometimes = 2.0
moreOften = 4.0
printData ("frequency - Generate an instance from an array of generators \
\where each generator is used unequally") $frequency$ unsafePartial fromJust $NEA.fromArray [ Tuple lessOften (elements$ array_1)
, Tuple sometimes (elements $array_2) , Tuple moreOften (elements$ array_4)
]

printData "suchThat - Create a generator (e.g. even numbers) by filtering \
\out invalid instances that are generated from another generator \
\by using the given function" $suchThat (chooseInt 1 100) even log "*** Multiplier combinators ***" printData "arrayOf - Using a generator that creates one a, create \ \an empty array of type a or \ \an array of randomly-generated a instances"$
arrayOf $chooseInt 0 9 printData "arrayOf1 - Using a generator that creates one a, create \ \an non-empty array of randomly-generated a instances"$
arrayOf1 $chooseInt 0 9 printData "vectorOf - Using a generator that creates one a, create \ \a non-empty array of a specified number of randomly-generated \ \a instances"$
vectorOf 10 $chooseInt 0 9 printData "listOf - Using a generator that creates one a, create \ \a non-empty list of a specified number of randomly-generated \ \a instances"$
listOf 10 $chooseInt 0 9 -- Helper functions printData :: forall a. Show a => String -> Gen a -> Effect Unit printData explanation generator = do log$ "=== " <> explanation
result <- randomSample generator
void $for result (\item -> log$ show item)
log "=== Finished\n"